@esfaenza/text-editors 19.2.9 → 19.2.11

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.
@@ -1,666 +1,542 @@
1
- import * as i0 from '@angular/core';
2
- import { InjectionToken, EventEmitter, inject, forwardRef, Output, Input, ViewEncapsulation, Component, input, viewChild } from '@angular/core';
3
- import * as i1 from '@angular/common';
4
1
  import { CommonModule } from '@angular/common';
2
+ import * as i0 from '@angular/core';
3
+ import { viewChild, input, booleanAttribute, EventEmitter, forwardRef, Output, ViewEncapsulation, Component, InjectionToken } from '@angular/core';
4
+ import * as i1 from '@angular/forms';
5
5
  import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
6
- import * as i2 from '@ckeditor/ckeditor5-angular';
7
- import { CKEditorModule, loadCKEditorCloud } from '@ckeditor/ckeditor5-angular';
8
-
9
- const TXE_DEBUG = new InjectionToken('TXE_DEBUG');
6
+ import { Extension, Editor } from '@tiptap/core';
7
+ import { Markdown } from '@tiptap/markdown';
8
+ import { StarterKit } from '@tiptap/starter-kit';
9
+ import { TextStyle } from '@tiptap/extension-text-style';
10
+ import { Color } from '@tiptap/extension-color';
11
+ import { Underline } from '@tiptap/extension-underline';
12
+ import { Table } from '@tiptap/extension-table';
13
+ import { TableRow } from '@tiptap/extension-table-row';
14
+ import { TableCell } from '@tiptap/extension-table-cell';
15
+ import { TableHeader } from '@tiptap/extension-table-header';
16
+ import { TextAlign } from '@tiptap/extension-text-align';
17
+ import Mention from '@tiptap/extension-mention';
18
+ import { marked } from 'marked';
19
+ import { Image } from '@tiptap/extension-image';
20
+ import { Plugin } from '@tiptap/pm/state';
10
21
 
11
- class HtmlEditorComponent {
12
- constructor() {
13
- this.Readonly = false; // Angular19 -> [disabled]
14
- this.Required = false;
15
- this.Validation = false;
16
- this.onEditorLoaded = new EventEmitter();
17
- this.EditorModel = null;
18
- this.DEBUG = inject(TXE_DEBUG, { optional: true }) || false;
19
- //#region Forms
20
- this.onTouched = () => { };
21
- this.propagateChange = (_) => { };
22
- }
23
- initializeEditor() {
24
- if (!this.PersistentEditor) {
25
- if (this.DEBUG)
26
- console.error("@ HTML-Editor @: Impossibile inizializzare l'editor HTML senza PersistentEditor");
27
- }
28
- else
29
- this.PersistentEditor?.iInitializeEditor("@", [], (source) => {
30
- this.onEditorLoaded.emit(source);
31
- });
32
- }
33
- ngOnInit() {
34
- if (this.DEBUG)
35
- console.info("@ HTML-Editor @: Il componente HtmlEditorComponent è stato creato");
36
- }
37
- ngOnDestroy() {
38
- if (this.DEBUG)
39
- console.info("@ HTML-Editor @: Il componente HtmlEditorComponent è stato distrutto");
40
- }
41
- registerOnChange(fn) {
42
- this.propagateChange = fn;
43
- }
44
- registerOnTouched(fn) {
45
- this.onTouched = fn;
46
- }
47
- writeValue(obj) {
48
- let value = "";
49
- if (obj !== undefined)
50
- value = obj;
51
- if (this.DEBUG)
52
- console.log("@ HTML-Editor @: Writevalue pre-refresh: " + value);
53
- if (value === this.EditorModel?.value) {
54
- if (this.DEBUG)
55
- console.log("@ HTML-Editor @: Writevalue ridondante");
56
- return;
57
- }
58
- this.EditorModel = null;
59
- requestAnimationFrame(() => {
60
- if (this.DEBUG)
61
- console.log("@ HTML-Editor @: Writevalue post-refresh: " + value);
62
- this.EditorModel = { value: value, onEditorChange: this.onEditorChange.bind(this) };
63
- });
64
- }
65
- validate(c) {
66
- let ret = null;
67
- if (this.EditorModel?.value || this.Readonly || !this.Required)
68
- ret = null;
69
- ret = null;
70
- if (this.DEBUG)
71
- console.log("@ HTML-Editor @: Validate post-validate: " + ret);
72
- return ret;
73
- }
74
- onEditorChange({ editor }) {
75
- if (!this.EditorModel)
76
- return;
77
- let data = editor?.getData();
78
- if (this.DEBUG)
79
- console.log("@ HTML-Editor @: changed: " + data);
80
- this.propagateChange(data);
81
- }
82
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HtmlEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
83
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: HtmlEditorComponent, isStandalone: true, selector: "html-editor", inputs: { PersistentEditor: "PersistentEditor", Readonly: "Readonly", Required: "Required", Validation: "Validation" }, outputs: { onEditorLoaded: "onEditorLoaded" }, providers: [
84
- { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HtmlEditorComponent), multi: true },
85
- { provide: NG_VALIDATORS, useExisting: forwardRef(() => HtmlEditorComponent), multi: true }
86
- ], ngImport: i0, template: "<div class=\"html-editor\" *ngIf=\"EditorModel && PersistentEditor\">\r\n <ng-content *ngIf=\"PersistentEditor.EditorTemplate()\">\r\n <ng-content *ngTemplateOutlet=\"PersistentEditor.EditorTemplate(); context: {$implicit: EditorModel}\"></ng-content>\r\n </ng-content>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.html-editor .ck-content{overflow-x:hidden!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CKEditorModule }], encapsulation: i0.ViewEncapsulation.None }); }
87
- }
88
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HtmlEditorComponent, decorators: [{
89
- type: Component,
90
- args: [{ selector: "html-editor", standalone: true, imports: [CommonModule, FormsModule, CKEditorModule], encapsulation: ViewEncapsulation.None, providers: [
91
- { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HtmlEditorComponent), multi: true },
92
- { provide: NG_VALIDATORS, useExisting: forwardRef(() => HtmlEditorComponent), multi: true }
93
- ], template: "<div class=\"html-editor\" *ngIf=\"EditorModel && PersistentEditor\">\r\n <ng-content *ngIf=\"PersistentEditor.EditorTemplate()\">\r\n <ng-content *ngTemplateOutlet=\"PersistentEditor.EditorTemplate(); context: {$implicit: EditorModel}\"></ng-content>\r\n </ng-content>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.html-editor .ck-content{overflow-x:hidden!important}\n"] }]
94
- }], propDecorators: { PersistentEditor: [{
95
- type: Input
96
- }], Readonly: [{
97
- type: Input
98
- }], Required: [{
99
- type: Input
100
- }], Validation: [{
101
- type: Input
102
- }], onEditorLoaded: [{
103
- type: Output
104
- }] } });
105
-
106
- class MarkdownEditorComponent {
107
- constructor() {
108
- this.Readonly = false; // Angular19 -> [disabled]
109
- this.Required = false;
110
- this.Validation = false;
111
- // Mention
112
- this.MentionMarker = "@";
113
- this.MentionEntities = [];
114
- this.onEditorLoaded = new EventEmitter();
115
- this.DEBUG = inject(TXE_DEBUG, { optional: true }) || false;
116
- this.EditorModel = null;
117
- //#region Forms
118
- this.onTouched = () => { };
119
- this.propagateChange = (_) => { };
120
- }
121
- get NormalizedMentionEntities() {
122
- return this.MentionEntities.map(m => {
123
- return { id: this.MentionMarker + m.id, description: m.description };
124
- });
125
- }
126
- initializeEditor() {
127
- if (!this.PersistentEditor) {
128
- if (this.DEBUG)
129
- console.error("@ Markdown-Editor @: Impossibile inizializzare l'editor HTML senza PersistentEditor");
130
- }
131
- else
132
- this.PersistentEditor?.iInitializeEditor(this.MentionMarker, this.NormalizedMentionEntities, (source) => {
133
- this.onEditorLoaded.emit(source);
134
- });
135
- }
136
- ngOnInit() {
137
- if (this.DEBUG)
138
- console.info("@ Markdown-Editor @: Il componente MarkdownEditor è stato creato");
139
- }
140
- ngOnDestroy() {
141
- if (this.DEBUG)
142
- console.info("@ Markdown-Editor @: Il componente MarkdownEditor è stato distrutto");
143
- }
144
- registerOnChange(fn) {
145
- this.propagateChange = fn;
146
- }
147
- registerOnTouched(fn) {
148
- this.onTouched = fn;
149
- }
150
- writeValue(obj) {
151
- let value = "";
152
- if (obj !== undefined)
153
- value = obj;
154
- if (this.DEBUG)
155
- console.log("@ Markdown-Editor @: Writevalue pre-refresh: " + value);
156
- if (value === this.EditorModel?.value) {
157
- if (this.DEBUG)
158
- console.log("@ Markdown-Editor @: Writevalue ridondante");
159
- return;
160
- }
161
- this.EditorModel = null;
162
- requestAnimationFrame(() => {
163
- if (this.DEBUG)
164
- console.log("@ Markdown-Editor @: Writevalue post-refresh: " + value);
165
- this.EditorModel = { value: value, onEditorChange: this.onEditorChange.bind(this) };
166
- });
167
- }
168
- validate(c) {
169
- let ret = null;
170
- if (this.EditorModel?.value || this.Readonly || !this.Required)
171
- ret = null;
172
- ret = null;
173
- if (this.DEBUG)
174
- console.log("@ Markdown-Editor @: Validate post-validate: " + ret);
175
- return ret;
176
- }
177
- onEditorChange({ editor }) {
178
- if (!this.EditorModel)
179
- return;
180
- let data = editor?.getData();
181
- if (this.DEBUG)
182
- console.log("@ Markdown-Editor @: changed: " + data);
183
- this.propagateChange(data);
184
- }
185
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MarkdownEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
186
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: MarkdownEditorComponent, isStandalone: true, selector: "markdown-editor", inputs: { PersistentEditor: "PersistentEditor", Readonly: "Readonly", Required: "Required", Validation: "Validation", MentionMarker: "MentionMarker", MentionEntities: "MentionEntities" }, outputs: { onEditorLoaded: "onEditorLoaded" }, providers: [
187
- { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MarkdownEditorComponent), multi: true },
188
- { provide: NG_VALIDATORS, useExisting: forwardRef(() => MarkdownEditorComponent), multi: true }
189
- ], ngImport: i0, template: "<div class=\"html-editor\" *ngIf=\"EditorModel && PersistentEditor\">\r\n <ng-content *ngIf=\"PersistentEditor.EditorTemplate()\">\r\n <ng-content *ngTemplateOutlet=\"PersistentEditor.EditorTemplate(); context: {$implicit: EditorModel}\"></ng-content>\r\n </ng-content>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.markdown-editor .ck-content{overflow-x:hidden!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CKEditorModule }], encapsulation: i0.ViewEncapsulation.None }); }
190
- }
191
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MarkdownEditorComponent, decorators: [{
192
- type: Component,
193
- args: [{ selector: "markdown-editor", standalone: true, imports: [CommonModule, FormsModule, CKEditorModule], encapsulation: ViewEncapsulation.None, providers: [
194
- { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MarkdownEditorComponent), multi: true },
195
- { provide: NG_VALIDATORS, useExisting: forwardRef(() => MarkdownEditorComponent), multi: true }
196
- ], template: "<div class=\"html-editor\" *ngIf=\"EditorModel && PersistentEditor\">\r\n <ng-content *ngIf=\"PersistentEditor.EditorTemplate()\">\r\n <ng-content *ngTemplateOutlet=\"PersistentEditor.EditorTemplate(); context: {$implicit: EditorModel}\"></ng-content>\r\n </ng-content>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.markdown-editor .ck-content{overflow-x:hidden!important}\n"] }]
197
- }], propDecorators: { PersistentEditor: [{
198
- type: Input
199
- }], Readonly: [{
200
- type: Input
201
- }], Required: [{
202
- type: Input
203
- }], Validation: [{
204
- type: Input
205
- }], MentionMarker: [{
206
- type: Input
207
- }], MentionEntities: [{
208
- type: Input
209
- }], onEditorLoaded: [{
210
- type: Output
211
- }] } });
22
+ const CustomMention = Mention.extend({
23
+ renderMarkdown(node) { return `@${node.attrs?.id || node.attrs?.label}`; },
24
+ parseMarkdown(token) { return { type: token.type, attrs: { id: token.text, label: token.text } }; },
25
+ });
26
+ marked.use({
27
+ extensions: [
28
+ {
29
+ name: 'mention', level: 'inline',
30
+ tokenizer(src) {
31
+ const match = /^@([\w-]+)/.exec(src);
32
+ if (!match)
33
+ return undefined;
34
+ return { type: 'mention', raw: match[0], text: match[1] };
35
+ },
36
+ renderer(token) { return token.raw; },
37
+ },
38
+ ],
39
+ });
40
+ const mymarked = marked;
212
41
 
213
- const cloudConfig$2 = {
214
- version: '46.1.1',
215
- translations: ['it']
42
+ let handleFiles = async (view, files) => {
43
+ const file = Array.from(files || []).find(f => f.type.startsWith('image/'));
44
+ if (!file)
45
+ return;
46
+ const reader = new FileReader();
47
+ reader.onload = () => {
48
+ const base64 = reader.result;
49
+ const img = new window.Image();
50
+ img.onload = () => {
51
+ const { schema } = view.state;
52
+ const node = schema.nodes.image.create({ src: base64, width: img.naturalWidth, float: "none" });
53
+ const tr = view.state.tr.replaceSelectionWith(node);
54
+ view.dispatch(tr);
55
+ };
56
+ img.src = base64;
57
+ };
58
+ reader.readAsDataURL(file);
216
59
  };
217
- const LICENSE_KEY$2 = 'eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE4MDQ5ODIzOTksImp0aSI6ImJkZDU4ZGM3LTlhYzgtNDA4Mi05ZDk3LTg3Yzc0NjEzMDlmNyIsInVzYWdlRW5kcG9pbnQiOiJodHRwczovL3Byb3h5LWV2ZW50LmNrZWRpdG9yLmNvbSIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsiY2xvdWQiLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwiZmVhdHVyZXMiOlsiRFJVUCIsIkRPIiwiRlAiLCJTQyIsIlRPQyIsIlRQTCIsIlBPRSIsIkNDIiwiTUYiLCJFMlAiLCJFMlciLCJNTEwiLCJTRUUiLCJFQ0giLCJFSVMiLCJMSCIsIkZPTyJdLCJ2YyI6IjdjZjg2OGYwIn0.vw-04yWGiTzZVSaGxQUGCxWXBUQXRJ0yB2ItqwvNnd7nEjMFC4d9kiDgbkzGnHgAjkiQEUqTzrM7b1z4cR6rhA';
218
- class HtmlEditorStandaloneComponent {
219
- constructor() {
220
- this.Readonly = false; // Angular19 -> [disabled]
221
- this.Required = false;
222
- this.Validation = false;
223
- this.onEditorLoaded = new EventEmitter();
224
- //#region CKEditor5
225
- this.Editor = null;
226
- this.EditorConfig = null;
227
- this.EditorModel = { editorDataText: '', };
228
- //#endregion
229
- //#region Forms
230
- this.onTouched = () => { };
231
- this.propagateChange = (_) => { };
232
- }
233
- initializeEditor() {
234
- if (!this.Editor) {
235
- loadCKEditorCloud(cloudConfig$2).then(this.internalInitializeEditor.bind(this));
236
- this.onEditorLoaded.emit();
237
- }
238
- }
239
- ngOnDestroy() {
240
- console.warn("Il componente HtmlEditorComponent è stato distrutto");
241
- }
242
- internalInitializeEditor(cloudConfig) {
243
- const { ClassicEditor,
244
- /* Plugins */
245
- Alignment, AutoImage, Autosave, Base64UploadAdapter, Bold, CloudServices, Essentials, GeneralHtmlSupport, Heading, ImageInline, ImageBlock, ImageInsert, ImageInsertViaUrl, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Italic, Link, List, Paragraph, PasteFromOffice, Underline, SourceEditing } = cloudConfig.CKEditor;
246
- this.Editor = ClassicEditor;
247
- this.EditorConfig = {
248
- toolbar: {
249
- items: ['heading', '|', 'bold', 'italic', 'underline', '|', 'undo', 'redo', '|', 'insertImage', 'imageStyle:block', 'imageStyle:alignLeft', 'imageStyle:alignRight', '|', 'sourceEditing'],
250
- shouldNotGroupWhenFull: false
60
+ const CustomImage = Image.extend({
61
+ draggable: true,
62
+ selectable: true,
63
+ addAttributes() {
64
+ return {
65
+ ...this.parent?.(),
66
+ width: { default: null, },
67
+ float: { default: "none" }, // 'left' | 'right' | 'none'
68
+ src: {
69
+ default: null,
70
+ parseHTML: element => { return element.getAttribute('src'); },
71
+ renderHTML: attributes => { return { src: attributes.src, }; },
251
72
  },
252
- plugins: [
253
- Alignment, AutoImage, Autosave, Base64UploadAdapter, Bold, CloudServices, Essentials, GeneralHtmlSupport,
254
- Heading, ImageInline, ImageBlock, ImageInsert, ImageInsertViaUrl, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Italic,
255
- Link, List, Paragraph, PasteFromOffice, Underline, SourceEditing
256
- ],
257
- heading: {
258
- options: [
259
- { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
260
- { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
261
- { model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' },
262
- { model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' },
263
- { model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' },
264
- { model: 'heading5', view: 'h5', title: 'Heading 5', class: 'ck-heading_heading5' },
265
- { model: 'heading6', view: 'h6', title: 'Heading 6', class: 'ck-heading_heading6' }
266
- ]
73
+ };
74
+ },
75
+ renderHTML({ HTMLAttributes }) {
76
+ const { float } = HTMLAttributes;
77
+ let style = '';
78
+ if (float === 'left')
79
+ style = 'float:left; display:block; margin-right: 10px';
80
+ else if (float === 'right')
81
+ style = 'float:right; display:block; margin-left: 10px';
82
+ else
83
+ style = `display: inline-block; float: none; vertical-align: middle;`;
84
+ return ['img', { ...HTMLAttributes, style }];
85
+ },
86
+ parseHTML() {
87
+ return [
88
+ {
89
+ tag: 'img[src]',
90
+ getAttrs: element => {
91
+ const el = element;
92
+ const src = el.getAttribute('src');
93
+ if (!src)
94
+ return false;
95
+ // allow both normal URLs AND base64
96
+ if (src.startsWith('http') || src.startsWith('data:image'))
97
+ return { src, float: el.style.float || null, width: el.style.width ? parseInt(el.style.width) : null, };
98
+ return false;
99
+ },
267
100
  },
268
- htmlSupport: {
269
- allow: [{ name: /^.*$/, styles: true, attributes: true, classes: true }]
101
+ ];
102
+ },
103
+ addProseMirrorPlugins: () => {
104
+ return [
105
+ new Plugin({
106
+ props: {
107
+ handleDrop: (view, event) => {
108
+ const files = event.dataTransfer?.files;
109
+ if (!files?.length)
110
+ return false;
111
+ handleFiles(view, files);
112
+ return true;
113
+ },
114
+ handlePaste: (view, event) => {
115
+ const files = event.clipboardData?.files;
116
+ if (!files?.length)
117
+ return false;
118
+ handleFiles(view, files);
119
+ return true;
120
+ },
121
+ },
122
+ })
123
+ ];
124
+ },
125
+ });
126
+ const CustomImageWithView = CustomImage.extend({
127
+ addNodeView: () => {
128
+ return ({ node, getPos, editor }) => {
129
+ let updateImage = (img, node) => {
130
+ img.draggable = false;
131
+ img.src = node.attrs.src;
132
+ img.style.width = node.attrs.width ? `${node.attrs.width}px` : '';
133
+ if (node.attrs.float === 'left' || node.attrs.float === 'right') {
134
+ img.style.display = 'block';
135
+ if (node.attrs.float === 'left')
136
+ img.style.margin = "0 10px 0 0";
137
+ else if (node.attrs.float === 'right')
138
+ img.style.margin = "0 0 0 10px";
139
+ }
140
+ else {
141
+ img.style.display = 'inline-block';
142
+ img.style.verticalAlign = 'middle';
143
+ }
144
+ };
145
+ let updateWrapper = (wrapper, node) => {
146
+ wrapper.draggable = true;
147
+ wrapper.contentEditable = "false";
148
+ wrapper.className = `img-wrapper`;
149
+ wrapper.style.float = node.attrs.float;
150
+ if (node.attrs.float === 'left' || node.attrs.float === 'right') {
151
+ wrapper.style.width = "auto";
152
+ wrapper.style.textAlign = "auto";
153
+ }
154
+ else {
155
+ wrapper.style.width = "100%";
156
+ wrapper.style.textAlign = "center";
157
+ }
158
+ };
159
+ const wrapper = document.createElement('div');
160
+ updateWrapper(wrapper, node);
161
+ const img = document.createElement('img');
162
+ updateImage(img, node);
163
+ const toolbar = document.createElement('div');
164
+ toolbar.className = "img-toolbar";
165
+ const btn = (t, fn) => {
166
+ const b = document.createElement('button');
167
+ b.textContent = t;
168
+ b.onclick = fn;
169
+ return b;
170
+ };
171
+ toolbar.append(btn('Centro', () => editor.view.dispatch(editor.view.state.tr.setNodeMarkup(getPos(), undefined, { ...node.attrs, ...{ float: 'none' } }))), btn('Sinistra', () => editor.view.dispatch(editor.view.state.tr.setNodeMarkup(getPos(), undefined, { ...node.attrs, ...{ float: 'left' } }))), btn('Destra', () => editor.view.dispatch(editor.view.state.tr.setNodeMarkup(getPos(), undefined, { ...node.attrs, ...{ float: 'right' } }))), btn('Elimina', () => {
172
+ const nodePos = getPos();
173
+ editor.view.dispatch(editor.view.state.tr.delete(nodePos, nodePos + node.nodeSize));
174
+ }));
175
+ // resize
176
+ let startX = 0;
177
+ let startW = 0;
178
+ const handle = document.createElement('div');
179
+ handle.className = "img-resize-handle";
180
+ handle.onmousedown = (e) => {
181
+ startX = e.clientX;
182
+ startW = img.offsetWidth;
183
+ let latestWidth = null;
184
+ let ticking = false;
185
+ const move = (e) => {
186
+ latestWidth = Math.max(80, startW + (e.clientX - startX));
187
+ if (!ticking) {
188
+ ticking = true;
189
+ requestAnimationFrame(() => {
190
+ const nodePos = getPos();
191
+ editor.view.dispatch(editor.view.state.tr.setNodeMarkup(nodePos, undefined, { ...node.attrs, width: latestWidth }));
192
+ ticking = false;
193
+ });
194
+ }
195
+ };
196
+ const up = () => {
197
+ window.removeEventListener('mousemove', move);
198
+ window.removeEventListener('mouseup', up);
199
+ };
200
+ window.addEventListener('mousemove', move);
201
+ window.addEventListener('mouseup', up);
202
+ // Per evitare che si attivi il drag dell'elemento sotto. Dal resizer si usa solo il resizer
203
+ e.preventDefault();
204
+ };
205
+ wrapper.append(img, toolbar, handle);
206
+ return {
207
+ dom: wrapper,
208
+ destroy() { wrapper.remove(); },
209
+ update(updatedNode) {
210
+ // different node type -> recreate NodeView
211
+ if (updatedNode.type !== node.type)
212
+ return false;
213
+ node = updatedNode;
214
+ updateImage(img, node);
215
+ updateWrapper(wrapper, node);
216
+ return true;
217
+ },
218
+ };
219
+ };
220
+ },
221
+ });
222
+
223
+ const FontFamily = Extension.create({
224
+ name: 'fontFamily',
225
+ addGlobalAttributes() {
226
+ return [
227
+ {
228
+ types: ['textStyle'],
229
+ attributes: {
230
+ fontFamily: {
231
+ default: null,
232
+ parseHTML: element => element.style.fontFamily,
233
+ renderHTML: attributes => {
234
+ if (!attributes.fontFamily)
235
+ return {};
236
+ return { style: `font-family: ${attributes.fontFamily}` };
237
+ },
238
+ },
239
+ },
270
240
  },
271
- image: {
272
- toolbar: ['imageStyle:block', 'imageStyle:side', '|', 'resizeImage:original'],
273
- insert: { type: 'auto' }
241
+ ];
242
+ },
243
+ addCommands() {
244
+ return {
245
+ setFontFamily: (fontFamily) => ({ chain }) => { return chain().setMark('textStyle', { fontFamily }).run(); },
246
+ unsetFontFamily: () => ({ chain }) => { return chain().setMark('textStyle', { fontFamily: null, }).removeEmptyTextStyle().run(); },
247
+ };
248
+ },
249
+ });
250
+
251
+ const LineHeight = Extension.create({
252
+ name: 'lineHeight',
253
+ addGlobalAttributes() {
254
+ return [
255
+ {
256
+ types: ['paragraph', 'heading'],
257
+ attributes: {
258
+ lineHeight: {
259
+ default: null,
260
+ parseHTML: element => element.style.lineHeight,
261
+ renderHTML: attributes => {
262
+ if (!attributes.lineHeight)
263
+ return {};
264
+ return { style: `line-height: ${attributes.lineHeight}` };
265
+ },
266
+ },
267
+ },
274
268
  },
275
- initialData: "",
276
- language: 'it',
277
- licenseKey: LICENSE_KEY$2,
278
- link: {
279
- addTargetToExternalLinks: true,
280
- defaultProtocol: 'https://',
281
- decorators: {
282
- toggleDownloadable: {
283
- mode: 'manual',
284
- label: 'Downloadable',
285
- attributes: { download: 'file' }
269
+ ];
270
+ },
271
+ addCommands() {
272
+ return {
273
+ setLineHeight: (lineHeight) => ({ commands }) => { return commands.updateAttributes('paragraph', { lineHeight }); },
274
+ unsetLineHeight: () => ({ commands }) => { return commands.updateAttributes('paragraph', { lineHeight: null }); },
275
+ };
276
+ },
277
+ });
278
+
279
+ let Suggestion = (choiches) => {
280
+ return {
281
+ char: '@',
282
+ items: ({ query }) => {
283
+ return choiches.filter(item => item.description.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5);
284
+ },
285
+ render: () => {
286
+ let popup;
287
+ let selectedIndex = 0;
288
+ let currentProps;
289
+ return {
290
+ onStart: (props) => {
291
+ popup = document.createElement('div');
292
+ popup.classList.add('suggestion-popup');
293
+ document.body.appendChild(popup);
294
+ currentProps = props;
295
+ updatePopup();
296
+ },
297
+ onKeyDown(props) {
298
+ if (props.event.key === 'ArrowUp') {
299
+ selectedIndex = (selectedIndex + currentProps.items.length - 1) % currentProps.items.length;
300
+ updatePopup();
301
+ return true;
286
302
  }
287
- }
303
+ if (props.event.key === 'ArrowDown') {
304
+ selectedIndex = (selectedIndex + 1) % currentProps.items.length;
305
+ updatePopup();
306
+ return true;
307
+ }
308
+ if (props.event.key === 'Enter') {
309
+ selectItem();
310
+ return true;
311
+ }
312
+ return false;
313
+ },
314
+ onUpdate(props) {
315
+ currentProps = props;
316
+ updatePopup();
317
+ },
318
+ onExit() { popup.remove(); },
319
+ };
320
+ function updatePopup() {
321
+ if (!currentProps.clientRect)
322
+ return;
323
+ popup.innerHTML = '';
324
+ currentProps.items.forEach((item, index) => {
325
+ const button = document.createElement('button');
326
+ button.textContent = item.description;
327
+ if (index === selectedIndex)
328
+ button.classList.add('is-selected');
329
+ button.addEventListener('click', () => {
330
+ selectedIndex = index;
331
+ selectItem();
332
+ });
333
+ popup.appendChild(button);
334
+ });
335
+ const rect = currentProps.clientRect();
336
+ popup.style.position = 'fixed';
337
+ popup.style.left = `${rect.left}px`;
338
+ popup.style.top = `${rect.bottom + 5}px`;
339
+ }
340
+ function selectItem() {
341
+ const item = currentProps.items[selectedIndex];
342
+ if (item)
343
+ currentProps.command({ id: item.id, description: item.description, });
344
+ }
345
+ }
346
+ };
347
+ };
348
+
349
+ const FontSize = Extension.create({
350
+ name: 'fontSize',
351
+ addGlobalAttributes() {
352
+ return [
353
+ {
354
+ types: ['textStyle'],
355
+ attributes: {
356
+ fontSize: {
357
+ default: null,
358
+ parseHTML: element => {
359
+ const size = element.style.fontSize;
360
+ if (!size)
361
+ return null;
362
+ // normalize pt → px
363
+ if (size.endsWith('pt'))
364
+ return `${Math.round(parseFloat(size) * 1.333)}px`;
365
+ return size;
366
+ },
367
+ renderHTML: attributes => {
368
+ if (!attributes.fontSize)
369
+ return {};
370
+ return { style: `font-size: ${attributes.fontSize}` };
371
+ },
372
+ },
373
+ },
288
374
  },
289
- placeholder: 'Scrivi o incolla il tuo contenuto qui!'
375
+ ];
376
+ },
377
+ addCommands() {
378
+ return {
379
+ setFontSize: (fontSize) => ({ chain }) => { return chain().setMark('textStyle', { fontSize }).run(); },
380
+ unsetFontSize: () => ({ chain }) => { return chain().setMark('textStyle', { fontSize: null }).removeEmptyTextStyle().run(); },
290
381
  };
291
- }
292
- onEditorChange({ editor }) {
293
- let data = editor?.getData();
294
- if (data !== undefined)
295
- this.propagateChange(data);
296
- }
297
- registerOnChange(fn) {
298
- this.propagateChange = fn;
299
- }
300
- registerOnTouched(fn) {
301
- this.onTouched = fn;
302
- }
303
- writeValue(obj) {
304
- if (obj !== undefined) {
305
- this.value = obj;
306
- }
307
- else
308
- this.value = "";
309
- }
310
- validate(c) {
311
- if (this.value || this.Readonly || !this.Required)
312
- return null;
313
- return null;
314
- }
315
- changed() {
316
- this.propagateChange(this.value);
317
- }
318
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HtmlEditorStandaloneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
319
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: HtmlEditorStandaloneComponent, isStandalone: true, selector: "html-editor-standalone", inputs: { PersistentEditor: "PersistentEditor", Readonly: "Readonly", Required: "Required", Validation: "Validation" }, outputs: { onEditorLoaded: "onEditorLoaded" }, providers: [
320
- { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HtmlEditorStandaloneComponent), multi: true },
321
- { provide: NG_VALIDATORS, useExisting: forwardRef(() => HtmlEditorStandaloneComponent), multi: true }
322
- ], ngImport: i0, template: "<div class=\"html-editor\">\r\n <ckeditor *ngIf=\"Editor && EditorConfig\"\r\n [data]=\"value\"\r\n [editor]=\"Editor\"\r\n [config]=\"EditorConfig\"\r\n (change)=\"onEditorChange($event)\">\r\n </ckeditor>\r\n <div *ngIf=\"!Editor && !EditorConfig\">\r\n Editor in caricamento...\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.html-editor .ck-content{overflow-x:hidden!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i2.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }], encapsulation: i0.ViewEncapsulation.None }); }
323
- }
324
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HtmlEditorStandaloneComponent, decorators: [{
325
- type: Component,
326
- args: [{ selector: "html-editor-standalone", standalone: true, imports: [CommonModule, FormsModule, CKEditorModule], encapsulation: ViewEncapsulation.None, providers: [
327
- { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => HtmlEditorStandaloneComponent), multi: true },
328
- { provide: NG_VALIDATORS, useExisting: forwardRef(() => HtmlEditorStandaloneComponent), multi: true }
329
- ], template: "<div class=\"html-editor\">\r\n <ckeditor *ngIf=\"Editor && EditorConfig\"\r\n [data]=\"value\"\r\n [editor]=\"Editor\"\r\n [config]=\"EditorConfig\"\r\n (change)=\"onEditorChange($event)\">\r\n </ckeditor>\r\n <div *ngIf=\"!Editor && !EditorConfig\">\r\n Editor in caricamento...\r\n </div>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.html-editor .ck-content{overflow-x:hidden!important}\n"] }]
330
- }], propDecorators: { PersistentEditor: [{
331
- type: Input
332
- }], Readonly: [{
333
- type: Input
334
- }], Required: [{
335
- type: Input
336
- }], Validation: [{
337
- type: Input
338
- }], onEditorLoaded: [{
339
- type: Output
340
- }] } });
382
+ },
383
+ });
341
384
 
342
- const cloudConfig$1 = {
343
- version: '46.1.1',
344
- translations: ['it']
345
- };
346
- const LICENSE_KEY$1 = 'eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE4MDQ5ODIzOTksImp0aSI6ImJkZDU4ZGM3LTlhYzgtNDA4Mi05ZDk3LTg3Yzc0NjEzMDlmNyIsInVzYWdlRW5kcG9pbnQiOiJodHRwczovL3Byb3h5LWV2ZW50LmNrZWRpdG9yLmNvbSIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsiY2xvdWQiLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwiZmVhdHVyZXMiOlsiRFJVUCIsIkRPIiwiRlAiLCJTQyIsIlRPQyIsIlRQTCIsIlBPRSIsIkNDIiwiTUYiLCJFMlAiLCJFMlciLCJNTEwiLCJTRUUiLCJFQ0giLCJFSVMiLCJMSCIsIkZPTyJdLCJ2YyI6IjdjZjg2OGYwIn0.vw-04yWGiTzZVSaGxQUGCxWXBUQXRJ0yB2ItqwvNnd7nEjMFC4d9kiDgbkzGnHgAjkiQEUqTzrM7b1z4cR6rhA';
347
- class MarkdownEditorStandaloneComponent {
385
+ class EditorComponent {
348
386
  constructor() {
349
- this.Readonly = false; // Angular19 -> [disabled]
350
- this.Required = false;
351
- this.Validation = false;
352
- // Mention
353
- this.MentionMarker = "@";
354
- this.MentionEntities = [];
355
- this.onEditorLoaded = new EventEmitter();
356
- //#region CKEditor5
357
- this.Editor = null;
358
- this.EditorConfig = null;
359
- this.EditorModel = { editorDataText: '', };
360
- //#endregion
361
- //#region Forms
387
+ this.onChange = (_) => { };
362
388
  this.onTouched = () => { };
363
- this.propagateChange = (_) => { };
389
+ this.element = viewChild.required("element");
390
+ this.EmojiSupport = input(false);
391
+ this.BulletListSupport = input(false);
392
+ this.TablesSupport = input(false);
393
+ this.Mode = input.required();
394
+ this.readonly = input(false, { transform: booleanAttribute });
395
+ this.disabled = input(false, { transform: booleanAttribute });
396
+ this.required = input(false, { transform: booleanAttribute });
397
+ this.MentionEntities = input([]);
398
+ this.name = input.required();
399
+ this.inputChange = new EventEmitter();
400
+ this.inputFocus = new EventEmitter();
401
+ this.inputFinalized = new EventEmitter();
402
+ }
403
+ registerOnChange(fn) { this.onChange = fn; }
404
+ registerOnTouched(fn) { this.onTouched = fn; }
405
+ validate(_) {
406
+ return null;
364
407
  }
365
- get mentionEntities() {
366
- return this.MentionEntities.map(m => {
367
- return { id: this.MentionMarker + m.id, description: m.description };
408
+ ngOnInit() {
409
+ let config = [];
410
+ config.push(...[
411
+ StarterKit,
412
+ TextStyle,
413
+ Color,
414
+ Underline,
415
+ FontSize,
416
+ FontFamily,
417
+ LineHeight,
418
+ TextAlign.configure({ types: ['heading', 'paragraph'] })
419
+ ]);
420
+ if (this.Mode() == "markdown")
421
+ config.push(Markdown.configure({ marked: mymarked }));
422
+ if (this.Mode() == "html") {
423
+ if (this.TablesSupport())
424
+ config.push(...[Table.configure({ lastColumnResizable: true, resizable: true }), TableRow, TableHeader, TableCell]);
425
+ config.push(CustomImageWithView);
426
+ }
427
+ if ((this.MentionEntities()?.length || 0) > 0)
428
+ config.push(CustomMention.configure({
429
+ deleteTriggerWithBackspace: true,
430
+ HTMLAttributes: { class: 'mention' },
431
+ suggestion: Suggestion(this.MentionEntities()),
432
+ }));
433
+ this.EditorRef = new Editor({
434
+ element: this.element().nativeElement,
435
+ extensions: config,
436
+ editable: !this.readonly(),
437
+ onUpdate: (_) => {
438
+ let value = "";
439
+ switch (this.Mode()) {
440
+ case "html":
441
+ value = this.EditorRef?.getHTML() || "";
442
+ // Emissione del valore vuoto trimmato per bene
443
+ if (value.trim() === "<p></p>")
444
+ value = "";
445
+ break;
446
+ case "markdown":
447
+ value = this.EditorRef?.getMarkdown() || "";
448
+ break;
449
+ case "text":
450
+ value = this.EditorRef?.getText() || "";
451
+ break;
452
+ }
453
+ this.onChange(value);
454
+ }
368
455
  });
369
456
  }
370
- initializeEditor() {
371
- if (!this.Editor) {
372
- loadCKEditorCloud(cloudConfig$1).then(this.internalInitializeEditor.bind(this));
373
- this.onEditorLoaded.emit();
457
+ async writeValue(obj) {
458
+ // Coercizione di tutti i valori "vuoti" all'unico "null"
459
+ if (obj === null || obj === undefined)
460
+ obj = null;
461
+ this.value = obj;
462
+ this.EditorRef?.commands.clearContent();
463
+ if (this.Mode() === "markdown")
464
+ this.EditorRef?.commands.setContent(this.value, { contentType: "markdown" });
465
+ else
466
+ this.EditorRef?.commands.insertContent(this.value);
467
+ }
468
+ setTypography(selectElement) {
469
+ switch (selectElement.target.value) {
470
+ case "paragraph":
471
+ this.EditorRef?.chain().focus().setParagraph().run();
472
+ break;
473
+ default:
474
+ this.EditorRef?.chain().focus().setHeading({ level: parseInt(selectElement.target.value.charAt(1)) }).run();
475
+ break;
374
476
  }
477
+ selectElement.target.value = "";
375
478
  }
376
- ngOnDestroy() {
377
- console.warn("Il componente MarkdownEditorComponent è stato distrutto");
479
+ setBold() {
480
+ this.EditorRef?.chain().focus().toggleBold().run();
378
481
  }
379
- internalInitializeEditor(cloudConfig) {
380
- const { ClassicEditor,
381
- /* Plugins */
382
- Alignment, AutoImage, Autosave, Base64UploadAdapter, Bold, CloudServices, Essentials, Heading, ImageInline, ImageBlock, ImageInsert, ImageInsertViaUrl, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Italic, Link, List, Paragraph, PasteFromOffice, Mention, Emoji, Markdown, PasteFromMarkdownExperimental } = cloudConfig.CKEditor;
383
- this.Editor = ClassicEditor;
384
- this.EditorConfig = {
385
- toolbar: {
386
- items: ['heading', '|', 'bold', 'italic', 'bulletedList', '|', 'undo', 'redo', '|', 'emoji'],
387
- shouldNotGroupWhenFull: false
388
- },
389
- plugins: [
390
- Alignment, AutoImage, Autosave, Base64UploadAdapter, Bold, CloudServices, Essentials, Heading,
391
- ImageInline, ImageBlock, ImageInsert, ImageInsertViaUrl, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Italic,
392
- Link, List, Paragraph, PasteFromOffice, Mention, Emoji, Markdown, PasteFromMarkdownExperimental
393
- ],
394
- heading: {
395
- options: [
396
- { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
397
- { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
398
- { model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' },
399
- { model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' },
400
- { model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' },
401
- { model: 'heading5', view: 'h5', title: 'Heading 5', class: 'ck-heading_heading5' },
402
- { model: 'heading6', view: 'h6', title: 'Heading 6', class: 'ck-heading_heading6' }
403
- ]
404
- },
405
- htmlSupport: {
406
- allow: [{ name: /^.*$/, styles: true, attributes: true, classes: true }]
407
- },
408
- image: {
409
- toolbar: ['imageStyle:block', 'imageStyle:side', '|', 'resizeImage:original'],
410
- insert: { type: 'auto' }
411
- },
412
- initialData: "",
413
- language: 'it',
414
- licenseKey: LICENSE_KEY$1,
415
- link: {
416
- addTargetToExternalLinks: true,
417
- defaultProtocol: 'https://',
418
- decorators: {
419
- toggleDownloadable: {
420
- mode: 'manual',
421
- label: 'Downloadable',
422
- attributes: { download: 'file' }
423
- }
424
- }
425
- },
426
- placeholder: 'Scrivi o incolla il tuo contenuto qui!'
427
- };
428
- // Attivo le Mention se sono presenti "MentionEntities"
429
- // "Mention" serve sempre per "Emoji"
430
- if (this.MentionEntities?.length > 0) {
431
- this.EditorConfig.mention = {
432
- feeds: [
433
- {
434
- marker: this.MentionMarker,
435
- feed: (filter) => {
436
- return this.mentionEntities.filter(t => t.id.toLowerCase().includes(filter.toLowerCase()));
437
- },
438
- minimumCharacters: 1,
439
- // Callback per stile
440
- itemRenderer: (item) => {
441
- let dropdownElement = document.createElement('div');
442
- dropdownElement.classList.add("ck-mention-dropdown");
443
- dropdownElement.id = `mention-list-item-id-${item.id}`;
444
- let useridElement = document.createElement('div');
445
- useridElement.classList.add("ck-username-id");
446
- useridElement.textContent = `${item.id.substr(1, item.id.length)}`;
447
- let userdescElement = document.createElement('div');
448
- userdescElement.textContent = ` ● ${item.description}`;
449
- dropdownElement.appendChild(useridElement);
450
- dropdownElement.appendChild(userdescElement);
451
- return dropdownElement;
452
- }
453
- },
454
- ]
455
- };
456
- }
482
+ setItalic() {
483
+ this.EditorRef?.chain().focus().toggleItalic().run();
457
484
  }
458
- onEditorChange({ editor }) {
459
- let data = editor?.getData();
460
- if (data !== undefined)
461
- this.propagateChange(data);
485
+ setUnderlined() {
486
+ this.EditorRef?.chain().focus().toggleUnderline().run();
462
487
  }
463
- registerOnChange(fn) {
464
- this.propagateChange = fn;
488
+ setBulletList() {
489
+ this.EditorRef?.chain().focus().toggleBulletList().run();
465
490
  }
466
- registerOnTouched(fn) {
467
- this.onTouched = fn;
491
+ undoAction() {
492
+ this.EditorRef?.chain().focus().undo().run();
468
493
  }
469
- writeValue(obj) {
470
- if (obj !== undefined) {
471
- this.value = obj;
472
- }
473
- else
474
- this.value = "";
494
+ redoAction() {
495
+ this.EditorRef?.chain().focus().redo().run();
475
496
  }
476
- validate(c) {
477
- if (this.value || this.Readonly || !this.Required)
478
- return null;
479
- return null;
497
+ addTable() {
498
+ this.EditorRef?.chain().focus().insertTable({ rows: 1, cols: 2, withHeaderRow: false }).run();
480
499
  }
481
- changed() {
482
- this.propagateChange(this.value);
500
+ deleteTable() {
501
+ this.EditorRef?.chain().focus().deleteTable().run();
483
502
  }
484
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MarkdownEditorStandaloneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
485
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: MarkdownEditorStandaloneComponent, isStandalone: true, selector: "markdown-editor-standalone", inputs: { Readonly: "Readonly", Required: "Required", Validation: "Validation", MentionMarker: "MentionMarker", MentionEntities: "MentionEntities", PersistentEditor: "PersistentEditor" }, outputs: { onEditorLoaded: "onEditorLoaded" }, providers: [
486
- {
487
- provide: NG_VALUE_ACCESSOR,
488
- useExisting: forwardRef(() => MarkdownEditorStandaloneComponent),
489
- multi: true
490
- },
491
- {
492
- provide: NG_VALIDATORS,
493
- useExisting: forwardRef(() => MarkdownEditorStandaloneComponent),
494
- multi: true
495
- }
496
- ], ngImport: i0, template: "<div class=\"markdown-editor\">\r\n <ckeditor *ngIf=\"Editor && EditorConfig\"\r\n [data]=\"value\"\r\n [editor]=\"Editor\"\r\n [config]=\"EditorConfig\"\r\n (change)=\"onEditorChange($event)\">\r\n </ckeditor>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.markdown-editor .ck-content{overflow-x:hidden!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i2.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }], encapsulation: i0.ViewEncapsulation.None }); }
497
- }
498
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MarkdownEditorStandaloneComponent, decorators: [{
499
- type: Component,
500
- args: [{ selector: "markdown-editor-standalone", standalone: true, imports: [CommonModule, FormsModule, CKEditorModule], encapsulation: ViewEncapsulation.None, providers: [
501
- {
502
- provide: NG_VALUE_ACCESSOR,
503
- useExisting: forwardRef(() => MarkdownEditorStandaloneComponent),
504
- multi: true
505
- },
506
- {
507
- provide: NG_VALIDATORS,
508
- useExisting: forwardRef(() => MarkdownEditorStandaloneComponent),
509
- multi: true
510
- }
511
- ], template: "<div class=\"markdown-editor\">\r\n <ckeditor *ngIf=\"Editor && EditorConfig\"\r\n [data]=\"value\"\r\n [editor]=\"Editor\"\r\n [config]=\"EditorConfig\"\r\n (change)=\"onEditorChange($event)\">\r\n </ckeditor>\r\n</div>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.markdown-editor .ck-content{overflow-x:hidden!important}\n"] }]
512
- }], propDecorators: { Readonly: [{
513
- type: Input
514
- }], Required: [{
515
- type: Input
516
- }], Validation: [{
517
- type: Input
518
- }], MentionMarker: [{
519
- type: Input
520
- }], MentionEntities: [{
521
- type: Input
522
- }], onEditorLoaded: [{
523
- type: Output
524
- }], PersistentEditor: [{
525
- type: Input
526
- }] } });
527
-
528
- const cloudConfig = {
529
- version: '46.1.1',
530
- translations: ['it']
531
- };
532
- const LICENSE_KEY = 'eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE4MDQ5ODIzOTksImp0aSI6ImJkZDU4ZGM3LTlhYzgtNDA4Mi05ZDk3LTg3Yzc0NjEzMDlmNyIsInVzYWdlRW5kcG9pbnQiOiJodHRwczovL3Byb3h5LWV2ZW50LmNrZWRpdG9yLmNvbSIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsiY2xvdWQiLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwiZmVhdHVyZXMiOlsiRFJVUCIsIkRPIiwiRlAiLCJTQyIsIlRPQyIsIlRQTCIsIlBPRSIsIkNDIiwiTUYiLCJFMlAiLCJFMlciLCJNTEwiLCJTRUUiLCJFQ0giLCJFSVMiLCJMSCIsIkZPTyJdLCJ2YyI6IjdjZjg2OGYwIn0.vw-04yWGiTzZVSaGxQUGCxWXBUQXRJ0yB2ItqwvNnd7nEjMFC4d9kiDgbkzGnHgAjkiQEUqTzrM7b1z4cR6rhA';
533
- class PersistentEditor {
534
- constructor() {
535
- this.Mode = input.required();
536
- this.EditorTemplate = viewChild("template");
537
- this.DEBUG = inject(TXE_DEBUG, { optional: true }) || false;
538
- this.OnEditorLoadedCallbackFunction = null;
539
- this.Editor = null;
540
- this.EditorConfig = null;
541
- this.MentionMarker = "@";
542
- this.MentionEntities = [];
503
+ addRow() {
504
+ this.EditorRef?.chain().focus().addRowAfter().run();
543
505
  }
544
- iInitializeEditor(mentionmarker, mentionentitis, onEditorLoaded) {
545
- if (onEditorLoaded)
546
- this.OnEditorLoadedCallbackFunction = onEditorLoaded;
547
- if (this.Editor && this.EditorConfig) {
548
- if (this.DEBUG)
549
- console.log("@ Persistent Editor @ Editor is already initialized");
550
- }
551
- else {
552
- loadCKEditorCloud(cloudConfig).then(this.internalInitializeEditor.bind(this));
553
- if (this.DEBUG)
554
- console.log(`@ Persistent Editor @ Editor is initialized (${this.Mode()} mode). loadCKEditorCloud has been called`);
555
- this.OnEditorLoadedCallbackFunction?.("initialize");
556
- }
557
- this.MentionMarker = mentionmarker ?? "@";
558
- this.MentionEntities = mentionentitis ?? [];
559
- if ((this.MentionEntities?.length || 0) > 0) {
560
- if (this.DEBUG)
561
- console.log(`@ Persistent Editor @ Editor is using ${this.MentionEntities?.length} mentions possibilities`);
562
- }
506
+ deleteRow() {
507
+ this.EditorRef?.chain().focus().deleteRow().run();
563
508
  }
564
- onReady() {
565
- this.OnEditorLoadedCallbackFunction?.("ready");
509
+ addColumn() {
510
+ this.EditorRef?.chain().focus().addColumnAfter().run();
566
511
  }
567
- internalInitializeEditor(cloudConfig) {
568
- const { ClassicEditor,
569
- // Plugin generali
570
- Alignment, AutoImage, Autosave, Base64UploadAdapter, Bold, CloudServices, Essentials, Heading, ImageInline, ImageBlock, ImageInsert, ImageInsertViaUrl, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Italic, Link, List, Paragraph, PasteFromOffice,
571
- // Plugin specifici modalità HTML
572
- GeneralHtmlSupport, Underline, SourceEditing,
573
- // Plugin specifici modalità Markdown
574
- Mention, Emoji, Markdown, PasteFromMarkdownExperimental } = cloudConfig.CKEditor;
575
- let markdownPlugins = [Mention, Emoji, Markdown, PasteFromMarkdownExperimental];
576
- let htmlPlugins = [GeneralHtmlSupport, Underline, SourceEditing];
577
- this.Editor = ClassicEditor;
578
- this.EditorConfig = {
579
- toolbar: {
580
- items: this.Mode() == "html" ?
581
- ['heading', '|', 'bold', 'italic', 'underline', '|', 'undo', 'redo', '|', 'insertImage', 'imageStyle:block', 'imageStyle:alignLeft', 'imageStyle:alignRight', '|', 'sourceEditing'] :
582
- ['heading', '|', 'bold', 'italic', 'bulletedList', '|', 'undo', 'redo', '|', 'emoji'],
583
- shouldNotGroupWhenFull: false
584
- },
585
- plugins: [
586
- Alignment, AutoImage, Autosave, Base64UploadAdapter, Bold, CloudServices, Essentials,
587
- Heading, ImageInline, ImageBlock, ImageInsert, ImageInsertViaUrl, ImageResize, ImageStyle, ImageToolbar, ImageUpload, Italic,
588
- Link, List, Paragraph, PasteFromOffice,
589
- ...(this.Mode() == "html" ? htmlPlugins : markdownPlugins)
590
- ],
591
- heading: {
592
- options: [
593
- { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
594
- { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
595
- { model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' },
596
- { model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' },
597
- { model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' },
598
- { model: 'heading5', view: 'h5', title: 'Heading 5', class: 'ck-heading_heading5' },
599
- { model: 'heading6', view: 'h6', title: 'Heading 6', class: 'ck-heading_heading6' }
600
- ]
601
- },
602
- htmlSupport: {
603
- allow: [{ name: /^.*$/, styles: true, attributes: true, classes: true }]
604
- },
605
- image: {
606
- toolbar: ['imageStyle:block', 'imageStyle:side', '|', 'resizeImage:original'],
607
- insert: { type: 'auto' }
608
- },
609
- initialData: "",
610
- language: 'it',
611
- licenseKey: LICENSE_KEY,
612
- link: {
613
- addTargetToExternalLinks: true,
614
- defaultProtocol: 'https://',
615
- decorators: {
616
- toggleDownloadable: {
617
- mode: 'manual',
618
- label: 'Downloadable',
619
- attributes: { download: 'file' }
620
- }
621
- }
622
- },
623
- placeholder: 'Scrivi o incolla il tuo contenuto qui!'
624
- };
625
- if (this.Mode() == "markdown")
626
- this.setupMentions();
512
+ deleteColumn() {
513
+ this.EditorRef?.chain().focus().deleteColumn().run();
627
514
  }
628
- setupMentions() {
629
- if (!this.EditorConfig)
630
- return;
631
- this.EditorConfig.mention = {
632
- feeds: [
633
- {
634
- marker: this.MentionMarker ?? "@",
635
- feed: (filter) => {
636
- return this.MentionEntities?.filter(t => t.id.toLowerCase().includes(filter.toLowerCase())) || [];
637
- },
638
- minimumCharacters: 1,
639
- // Callback per stile
640
- itemRenderer: (item) => {
641
- let dropdownElement = document.createElement('div');
642
- dropdownElement.classList.add("ck-mention-dropdown");
643
- dropdownElement.id = `mention-list-item-id-${item.id}`;
644
- let useridElement = document.createElement('div');
645
- useridElement.classList.add("ck-username-id");
646
- useridElement.textContent = `${item.id.substr(1, item.id.length)}`;
647
- let userdescElement = document.createElement('div');
648
- userdescElement.textContent = ` ● ${item.description}`;
649
- dropdownElement.appendChild(useridElement);
650
- dropdownElement.appendChild(userdescElement);
651
- return dropdownElement;
652
- }
653
- },
654
- ]
655
- };
515
+ setEmoji(selectElement) {
516
+ this.EditorRef?.chain().focus().insertContent(selectElement.target.value).run();
517
+ selectElement.target.value = "";
656
518
  }
657
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PersistentEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
658
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.15", type: PersistentEditor, isStandalone: true, selector: "persistent-ckeditor", inputs: { Mode: { classPropertyName: "Mode", publicName: "Mode", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "EditorTemplate", first: true, predicate: ["template"], descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #template let-EditorModel>\r\n <ckeditor \r\n *ngIf=\"Editor && EditorConfig\" \r\n [editor]=\"Editor\" \r\n [config]=\"EditorConfig\" \r\n [data]=\"EditorModel.value\" \r\n (ready)=\"onReady()\"\r\n (change)=\"EditorModel.onEditorChange($event)\"></ckeditor>\r\n</ng-template>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.html-editor .ck-content{overflow-x:hidden!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i2.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }], encapsulation: i0.ViewEncapsulation.None }); }
519
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: EditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
520
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: EditorComponent, isStandalone: true, selector: "es-editor", inputs: { EmojiSupport: { classPropertyName: "EmojiSupport", publicName: "EmojiSupport", isSignal: true, isRequired: false, transformFunction: null }, BulletListSupport: { classPropertyName: "BulletListSupport", publicName: "BulletListSupport", isSignal: true, isRequired: false, transformFunction: null }, TablesSupport: { classPropertyName: "TablesSupport", publicName: "TablesSupport", isSignal: true, isRequired: false, transformFunction: null }, Mode: { classPropertyName: "Mode", publicName: "Mode", isSignal: true, isRequired: true, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, MentionEntities: { classPropertyName: "MentionEntities", publicName: "MentionEntities", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { inputChange: "inputChange", inputFocus: "inputFocus", inputFinalized: "inputFinalized" }, providers: [
521
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => EditorComponent), multi: true },
522
+ { provide: NG_VALIDATORS, useExisting: forwardRef(() => EditorComponent), multi: true }
523
+ ], viewQueries: [{ propertyName: "element", first: true, predicate: ["element"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"editor-shell\">\r\n <div class=\"editor-toolbar\">\r\n\r\n <!-- Typography -->\r\n <select id=\"heading-select\" (change)=\"setTypography($event)\">\r\n <option value=\"\" selected hidden>Pragrafo</option>\r\n <option value=\"paragraph\">Pragrafo</option>\r\n <option value=\"h1\">Intestazione 1</option>\r\n <option value=\"h2\">Intestazione 2</option>\r\n <option value=\"h3\">Intestazione 3</option>\r\n <option value=\"h4\">Intestazione 4</option>\r\n <option value=\"h5\">Intestazione 5</option>\r\n <option value=\"h6\">Intestazione 6</option>\r\n </select>\r\n\r\n <div class=\"divider\"></div>\r\n\r\n <!-- Formatting -->\r\n <button (click)=\"setBold()\"><b>B</b></button>\r\n <button (click)=\"setItalic()\"><i>I</i></button>\r\n <button (click)=\"setUnderlined()\"><u>U</u></button>\r\n\r\n <!-- Lists -->\r\n @if(BulletListSupport()){\r\n <button (click)=\"setBulletList()\">\u2022 Lista</button>\r\n }\r\n\r\n <div class=\"divider\"></div>\r\n\r\n @if(Mode() == \"html\" && TablesSupport())\r\n {\r\n <button (click)=\"addTable()\">\u229E<span style=\"font-size: 10px;\">\u271A</span></button>\r\n <button (click)=\"deleteTable()\">\u229E<span style=\"font-size: 10px;\">\u25AC</span></button>\r\n <button (click)=\"addRow()\">\uD83D\uDDA8<span style=\"font-size: 10px;\">\u271A</span></button>\r\n <button (click)=\"deleteRow()\">\uD83D\uDDA8<span style=\"font-size: 10px;\">\u25AC</span></button>\r\n <button (click)=\"addColumn()\">\uD83D\uDDC4<span style=\"font-size: 10px;\">\u271A</span></button>\r\n <button (click)=\"deleteColumn()\">\uD83D\uDDC4<span style=\"font-size: 10px;\">\u25AC</span></button>\r\n <div class=\"divider\"></div>\r\n }\r\n\r\n <!-- History -->\r\n <button (click)=\"undoAction()\">\u21B6</button>\r\n <button (click)=\"redoAction()\">\u21B7</button>\r\n\r\n @if(EmojiSupport()){\r\n <select id=\"emoji-select\" (change)=\"setEmoji($event)\">\r\n <option value=\"\" hidden selected>\uD83D\uDE0A</option>\r\n <option value=\"\uD83D\uDE0A\">\uD83D\uDE0A</option>\r\n <option value=\"\uD83D\uDE00\">\uD83D\uDE00</option>\r\n <option value=\"\uD83D\uDE02\">\uD83D\uDE02</option>\r\n <option value=\"\uD83D\uDD25\">\uD83D\uDD25</option>\r\n <option value=\"\uD83C\uDF89\">\uD83C\uDF89</option>\r\n <option value=\"\uD83D\uDE80\">\uD83D\uDE80</option>\r\n <option value=\"\u2764\uFE0F\">\u2764\uFE0F</option>\r\n <option value=\"\uD83D\uDC4D\">\uD83D\uDC4D</option>\r\n </select>\r\n }\r\n </div>\r\n\r\n <div #element></div>\r\n</div>", styles: [".editor-shell{border:1px solid #dcdcdc;border-radius:10px;background:#fff;overflow:hidden;isolation:isolate;box-shadow:0 1px 2px #0000000a,0 6px 24px #0000000d;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.editor-toolbar{display:flex;align-items:center;gap:4px;padding:4px;background:linear-gradient(to bottom,#fafafa,#f3f3f3);border-bottom:1px solid #e5e5e5;flex-wrap:wrap}.editor-toolbar button{display:inline-flex;align-items:center;justify-content:center;line-height:1;min-width:36px;height:36px;padding:0 12px;border:1px solid #ddd;border-radius:8px;background:transparent;color:#333;font-size:18px;font-weight:500;cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease}.editor-toolbar button:hover{background:#e9e9e9}.editor-toolbar button:active{transform:translateY(1px)}.editor-toolbar button.is-active{background:#dfe7ff;border-color:#c7d2fe;color:#2342c0}.editor-toolbar select{height:36px;padding:0 12px;border:1px solid #d6d6d6;border-radius:8px;background:#fff;font-size:14px;color:#222;cursor:pointer;transition:border-color .12s ease,box-shadow .12s ease,background .12s ease}.editor-toolbar select:hover{background:#fafafa}.editor-toolbar select:focus{outline:none;border-color:#8ba8ff;box-shadow:0 0 0 3px #6082ff26}.editor-toolbar .divider{width:1px;height:24px;background:#ddd;margin:0 2px}.ProseMirror{min-height:60px;padding:12px;outline:none;font-size:16px;line-height:1.7;color:#1f1f1f;caret-color:#2563eb}.ProseMirror h1,.ProseMirror h2,.ProseMirror h3{line-height:1.2;margin-top:.8em;margin-bottom:.4em;font-weight:700;letter-spacing:-.02em}.ProseMirror h1{font-size:2rem}.ProseMirror h2{font-size:1.5rem}.ProseMirror h3{font-size:1.25rem}.ProseMirror p{margin:0}.ProseMirror ul,.ProseMirror ol{padding-left:1.5rem;margin:5px 0}.ProseMirror li{margin:0}.ProseMirror blockquote{margin:1.4rem 0;padding-left:1rem;border-left:4px solid #c7d2fe;color:#555}.ProseMirror code{background:#f3f4f6;color:#d63384;padding:.15em .35em;border-radius:4px;font-size:.92em}.ProseMirror pre{background:#1f2937;color:#f9fafb;padding:16px 18px;border-radius:10px;overflow-x:auto;margin:1.2rem 0}.ProseMirror pre code{background:transparent;color:inherit;padding:0}.ProseMirror a{color:#2563eb;text-decoration:underline}.ProseMirror hr{border:none;border-top:1px solid #e2e2e2;margin:2rem 0}.ProseMirror table{width:100%;border-collapse:collapse;margin:1.2rem 0}.ProseMirror th,.ProseMirror td{border:1px solid #ddd;padding:5px;position:relative}.ProseMirror th{background:#f5f5f5;text-align:left}.ProseMirror .column-resize-handle{position:absolute;top:0;right:-2px;width:5px;height:100%;cursor:col-resize;background:transparent;z-index:20}.ProseMirror ::selection{background:#6082ff40}.suggestion-popup{display:flex;flex-direction:column;min-width:220px;padding:6px;background:#fff;border:1px solid #e5e5e5;border-radius:10px;box-shadow:0 12px 30px #00000014,0 2px 8px #0000000d;z-index:1000}.suggestion-popup button{border:none;background:transparent;border-radius:8px;padding:8px 10px;text-align:left;cursor:pointer;font-size:14px}.suggestion-popup button:hover,.suggestion-popup button.is-selected{background:#eef2ff}.mention{display:inline-flex;align-items:center;background:#eef2ff;color:#304ffe;padding:2px 6px;border-radius:5px;font-weight:500}.img-wrapper{position:relative;display:inline-block;margin:12px 0}.img-wrapper img{max-width:100%;border-radius:10px;transition:opacity .2s ease}.img-toolbar{position:absolute;top:8px;left:8px;display:flex;gap:6px;background:#fffffff2;border:1px solid #e5e5e5;border-radius:8px;padding:4px;box-shadow:0 8px 20px #00000014}.img-toolbar button{border:none;background:transparent;padding:4px 6px;cursor:pointer;font-size:12px}.img-toolbar button:hover{background:#eef2ff;border-radius:6px}.img-resize-handle{position:absolute;right:0;bottom:0;width:12px;height:12px;background:#2563eb;border-radius:3px;cursor:se-resize}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }], encapsulation: i0.ViewEncapsulation.None }); }
659
524
  }
660
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PersistentEditor, decorators: [{
525
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: EditorComponent, decorators: [{
661
526
  type: Component,
662
- args: [{ selector: "persistent-ckeditor", standalone: true, imports: [CommonModule, FormsModule, CKEditorModule], encapsulation: ViewEncapsulation.None, template: "<ng-template #template let-EditorModel>\r\n <ckeditor \r\n *ngIf=\"Editor && EditorConfig\" \r\n [editor]=\"Editor\" \r\n [config]=\"EditorConfig\" \r\n [data]=\"EditorModel.value\" \r\n (ready)=\"onReady()\"\r\n (change)=\"EditorModel.onEditorChange($event)\"></ckeditor>\r\n</ng-template>", styles: ["@import\"https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap\";:root{--ck-content-font-family: \"Lato\"}@media print{body{margin:0!important}}.main-container{font-family:var(--ck-content-font-family);width:fit-content;margin-left:auto;margin-right:auto}.editor-container_classic-editor .editor-container__editor{min-width:795px;max-width:795px}.html-editor .ck-content{overflow-x:hidden!important}\n"] }]
663
- }] });
527
+ args: [{ selector: "es-editor", standalone: true, imports: [CommonModule, FormsModule], encapsulation: ViewEncapsulation.None, providers: [
528
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => EditorComponent), multi: true },
529
+ { provide: NG_VALIDATORS, useExisting: forwardRef(() => EditorComponent), multi: true }
530
+ ], template: "<div class=\"editor-shell\">\r\n <div class=\"editor-toolbar\">\r\n\r\n <!-- Typography -->\r\n <select id=\"heading-select\" (change)=\"setTypography($event)\">\r\n <option value=\"\" selected hidden>Pragrafo</option>\r\n <option value=\"paragraph\">Pragrafo</option>\r\n <option value=\"h1\">Intestazione 1</option>\r\n <option value=\"h2\">Intestazione 2</option>\r\n <option value=\"h3\">Intestazione 3</option>\r\n <option value=\"h4\">Intestazione 4</option>\r\n <option value=\"h5\">Intestazione 5</option>\r\n <option value=\"h6\">Intestazione 6</option>\r\n </select>\r\n\r\n <div class=\"divider\"></div>\r\n\r\n <!-- Formatting -->\r\n <button (click)=\"setBold()\"><b>B</b></button>\r\n <button (click)=\"setItalic()\"><i>I</i></button>\r\n <button (click)=\"setUnderlined()\"><u>U</u></button>\r\n\r\n <!-- Lists -->\r\n @if(BulletListSupport()){\r\n <button (click)=\"setBulletList()\">\u2022 Lista</button>\r\n }\r\n\r\n <div class=\"divider\"></div>\r\n\r\n @if(Mode() == \"html\" && TablesSupport())\r\n {\r\n <button (click)=\"addTable()\">\u229E<span style=\"font-size: 10px;\">\u271A</span></button>\r\n <button (click)=\"deleteTable()\">\u229E<span style=\"font-size: 10px;\">\u25AC</span></button>\r\n <button (click)=\"addRow()\">\uD83D\uDDA8<span style=\"font-size: 10px;\">\u271A</span></button>\r\n <button (click)=\"deleteRow()\">\uD83D\uDDA8<span style=\"font-size: 10px;\">\u25AC</span></button>\r\n <button (click)=\"addColumn()\">\uD83D\uDDC4<span style=\"font-size: 10px;\">\u271A</span></button>\r\n <button (click)=\"deleteColumn()\">\uD83D\uDDC4<span style=\"font-size: 10px;\">\u25AC</span></button>\r\n <div class=\"divider\"></div>\r\n }\r\n\r\n <!-- History -->\r\n <button (click)=\"undoAction()\">\u21B6</button>\r\n <button (click)=\"redoAction()\">\u21B7</button>\r\n\r\n @if(EmojiSupport()){\r\n <select id=\"emoji-select\" (change)=\"setEmoji($event)\">\r\n <option value=\"\" hidden selected>\uD83D\uDE0A</option>\r\n <option value=\"\uD83D\uDE0A\">\uD83D\uDE0A</option>\r\n <option value=\"\uD83D\uDE00\">\uD83D\uDE00</option>\r\n <option value=\"\uD83D\uDE02\">\uD83D\uDE02</option>\r\n <option value=\"\uD83D\uDD25\">\uD83D\uDD25</option>\r\n <option value=\"\uD83C\uDF89\">\uD83C\uDF89</option>\r\n <option value=\"\uD83D\uDE80\">\uD83D\uDE80</option>\r\n <option value=\"\u2764\uFE0F\">\u2764\uFE0F</option>\r\n <option value=\"\uD83D\uDC4D\">\uD83D\uDC4D</option>\r\n </select>\r\n }\r\n </div>\r\n\r\n <div #element></div>\r\n</div>", styles: [".editor-shell{border:1px solid #dcdcdc;border-radius:10px;background:#fff;overflow:hidden;isolation:isolate;box-shadow:0 1px 2px #0000000a,0 6px 24px #0000000d;font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}.editor-toolbar{display:flex;align-items:center;gap:4px;padding:4px;background:linear-gradient(to bottom,#fafafa,#f3f3f3);border-bottom:1px solid #e5e5e5;flex-wrap:wrap}.editor-toolbar button{display:inline-flex;align-items:center;justify-content:center;line-height:1;min-width:36px;height:36px;padding:0 12px;border:1px solid #ddd;border-radius:8px;background:transparent;color:#333;font-size:18px;font-weight:500;cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease}.editor-toolbar button:hover{background:#e9e9e9}.editor-toolbar button:active{transform:translateY(1px)}.editor-toolbar button.is-active{background:#dfe7ff;border-color:#c7d2fe;color:#2342c0}.editor-toolbar select{height:36px;padding:0 12px;border:1px solid #d6d6d6;border-radius:8px;background:#fff;font-size:14px;color:#222;cursor:pointer;transition:border-color .12s ease,box-shadow .12s ease,background .12s ease}.editor-toolbar select:hover{background:#fafafa}.editor-toolbar select:focus{outline:none;border-color:#8ba8ff;box-shadow:0 0 0 3px #6082ff26}.editor-toolbar .divider{width:1px;height:24px;background:#ddd;margin:0 2px}.ProseMirror{min-height:60px;padding:12px;outline:none;font-size:16px;line-height:1.7;color:#1f1f1f;caret-color:#2563eb}.ProseMirror h1,.ProseMirror h2,.ProseMirror h3{line-height:1.2;margin-top:.8em;margin-bottom:.4em;font-weight:700;letter-spacing:-.02em}.ProseMirror h1{font-size:2rem}.ProseMirror h2{font-size:1.5rem}.ProseMirror h3{font-size:1.25rem}.ProseMirror p{margin:0}.ProseMirror ul,.ProseMirror ol{padding-left:1.5rem;margin:5px 0}.ProseMirror li{margin:0}.ProseMirror blockquote{margin:1.4rem 0;padding-left:1rem;border-left:4px solid #c7d2fe;color:#555}.ProseMirror code{background:#f3f4f6;color:#d63384;padding:.15em .35em;border-radius:4px;font-size:.92em}.ProseMirror pre{background:#1f2937;color:#f9fafb;padding:16px 18px;border-radius:10px;overflow-x:auto;margin:1.2rem 0}.ProseMirror pre code{background:transparent;color:inherit;padding:0}.ProseMirror a{color:#2563eb;text-decoration:underline}.ProseMirror hr{border:none;border-top:1px solid #e2e2e2;margin:2rem 0}.ProseMirror table{width:100%;border-collapse:collapse;margin:1.2rem 0}.ProseMirror th,.ProseMirror td{border:1px solid #ddd;padding:5px;position:relative}.ProseMirror th{background:#f5f5f5;text-align:left}.ProseMirror .column-resize-handle{position:absolute;top:0;right:-2px;width:5px;height:100%;cursor:col-resize;background:transparent;z-index:20}.ProseMirror ::selection{background:#6082ff40}.suggestion-popup{display:flex;flex-direction:column;min-width:220px;padding:6px;background:#fff;border:1px solid #e5e5e5;border-radius:10px;box-shadow:0 12px 30px #00000014,0 2px 8px #0000000d;z-index:1000}.suggestion-popup button{border:none;background:transparent;border-radius:8px;padding:8px 10px;text-align:left;cursor:pointer;font-size:14px}.suggestion-popup button:hover,.suggestion-popup button.is-selected{background:#eef2ff}.mention{display:inline-flex;align-items:center;background:#eef2ff;color:#304ffe;padding:2px 6px;border-radius:5px;font-weight:500}.img-wrapper{position:relative;display:inline-block;margin:12px 0}.img-wrapper img{max-width:100%;border-radius:10px;transition:opacity .2s ease}.img-toolbar{position:absolute;top:8px;left:8px;display:flex;gap:6px;background:#fffffff2;border:1px solid #e5e5e5;border-radius:8px;padding:4px;box-shadow:0 8px 20px #00000014}.img-toolbar button{border:none;background:transparent;padding:4px 6px;cursor:pointer;font-size:12px}.img-toolbar button:hover{background:#eef2ff;border-radius:6px}.img-resize-handle{position:absolute;right:0;bottom:0;width:12px;height:12px;background:#2563eb;border-radius:3px;cursor:se-resize}\n"] }]
531
+ }], propDecorators: { inputChange: [{
532
+ type: Output
533
+ }], inputFocus: [{
534
+ type: Output
535
+ }], inputFinalized: [{
536
+ type: Output
537
+ }] } });
538
+
539
+ const TXE_DEBUG = new InjectionToken('TXE_DEBUG');
664
540
 
665
541
  /*
666
542
  * Public API Surface of text-editors
@@ -670,5 +546,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
670
546
  * Generated bundle index. Do not edit.
671
547
  */
672
548
 
673
- export { HtmlEditorComponent, HtmlEditorStandaloneComponent, MarkdownEditorComponent, MarkdownEditorStandaloneComponent, PersistentEditor, TXE_DEBUG };
549
+ export { EditorComponent, TXE_DEBUG };
674
550
  //# sourceMappingURL=esfaenza-text-editors.mjs.map