@stackch/angular-richtext-editor 1.2.0 → 1.2.1
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,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { EventEmitter, Output, Input, Component,
|
|
2
|
+
import { EventEmitter, Output, Input, Component, HostListener, ViewChild, Directive, forwardRef } from '@angular/core';
|
|
3
3
|
import { CommonModule } from '@angular/common';
|
|
4
4
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
5
5
|
|
|
@@ -126,6 +126,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
126
126
|
type: Output
|
|
127
127
|
}] } });
|
|
128
128
|
|
|
129
|
+
// ─── Config & Types ───────────────────────────────────────────────────────────
|
|
129
130
|
class StackchRichtextEditorConfig {
|
|
130
131
|
// Sichtbarkeit einzelner Toolbar-Elemente (Default: an)
|
|
131
132
|
showUndoRedo = true;
|
|
@@ -183,12 +184,10 @@ class StackchRichtextEditorI18n {
|
|
|
183
184
|
h5Label = 'H5';
|
|
184
185
|
h6Label = 'H6';
|
|
185
186
|
}
|
|
186
|
-
// Predefined i18n bundles
|
|
187
|
+
// ─── Predefined i18n bundles ──────────────────────────────────────────────────
|
|
187
188
|
// Consumers can import these and pass via config.i18n to localize the toolbar/labels.
|
|
188
189
|
const STACKCH_RTE_I18N_DE = {
|
|
189
|
-
// Generic
|
|
190
190
|
placeholder: 'Schreiben…',
|
|
191
|
-
// Toolbar titles
|
|
192
191
|
undoTitle: 'Rückgängig (Strg+Z)',
|
|
193
192
|
redoTitle: 'Wiederholen (Strg+Y)',
|
|
194
193
|
fontPanelTitle: 'Schrift & Größe',
|
|
@@ -215,20 +214,13 @@ const STACKCH_RTE_I18N_DE = {
|
|
|
215
214
|
alignJustifyTitle: 'Blocksatz',
|
|
216
215
|
linkTitle: 'Link',
|
|
217
216
|
removeFormatTitle: 'Formatierung entfernen',
|
|
218
|
-
// Heading menu labels
|
|
219
217
|
paragraphLabel: 'Absatz (P)',
|
|
220
218
|
codeLabel: 'Code (pre)',
|
|
221
|
-
h1Label: 'H1',
|
|
222
|
-
|
|
223
|
-
h3Label: 'H3',
|
|
224
|
-
h4Label: 'H4',
|
|
225
|
-
h5Label: 'H5',
|
|
226
|
-
h6Label: 'H6',
|
|
219
|
+
h1Label: 'H1', h2Label: 'H2', h3Label: 'H3',
|
|
220
|
+
h4Label: 'H4', h5Label: 'H5', h6Label: 'H6',
|
|
227
221
|
};
|
|
228
222
|
const STACKCH_RTE_I18N_FR = {
|
|
229
|
-
// Generic
|
|
230
223
|
placeholder: 'Écrire…',
|
|
231
|
-
// Toolbar titles
|
|
232
224
|
undoTitle: 'Annuler (Ctrl+Z)',
|
|
233
225
|
redoTitle: 'Rétablir (Ctrl+Y)',
|
|
234
226
|
fontPanelTitle: 'Police et taille',
|
|
@@ -255,20 +247,13 @@ const STACKCH_RTE_I18N_FR = {
|
|
|
255
247
|
alignJustifyTitle: 'Justifié',
|
|
256
248
|
linkTitle: 'Lien',
|
|
257
249
|
removeFormatTitle: 'Effacer la mise en forme',
|
|
258
|
-
// Heading menu labels
|
|
259
250
|
paragraphLabel: 'Paragraphe (P)',
|
|
260
251
|
codeLabel: 'Code (pre)',
|
|
261
|
-
h1Label: 'H1',
|
|
262
|
-
|
|
263
|
-
h3Label: 'H3',
|
|
264
|
-
h4Label: 'H4',
|
|
265
|
-
h5Label: 'H5',
|
|
266
|
-
h6Label: 'H6',
|
|
252
|
+
h1Label: 'H1', h2Label: 'H2', h3Label: 'H3',
|
|
253
|
+
h4Label: 'H4', h5Label: 'H5', h6Label: 'H6',
|
|
267
254
|
};
|
|
268
255
|
const STACKCH_RTE_I18N_IT = {
|
|
269
|
-
// Generic
|
|
270
256
|
placeholder: 'Scrivi…',
|
|
271
|
-
// Toolbar titles
|
|
272
257
|
undoTitle: 'Annulla (Ctrl+Z)',
|
|
273
258
|
redoTitle: 'Ripristina (Ctrl+Y)',
|
|
274
259
|
fontPanelTitle: 'Carattere e dimensione',
|
|
@@ -295,18 +280,22 @@ const STACKCH_RTE_I18N_IT = {
|
|
|
295
280
|
alignJustifyTitle: 'Giustificato',
|
|
296
281
|
linkTitle: 'Collegamento',
|
|
297
282
|
removeFormatTitle: 'Rimuovi formattazione',
|
|
298
|
-
// Heading menu labels
|
|
299
283
|
paragraphLabel: 'Paragrafo (P)',
|
|
300
284
|
codeLabel: 'Codice (pre)',
|
|
301
|
-
h1Label: 'H1',
|
|
302
|
-
|
|
303
|
-
h3Label: 'H3',
|
|
304
|
-
h4Label: 'H4',
|
|
305
|
-
h5Label: 'H5',
|
|
306
|
-
h6Label: 'H6',
|
|
285
|
+
h1Label: 'H1', h2Label: 'H2', h3Label: 'H3',
|
|
286
|
+
h4Label: 'H4', h5Label: 'H5', h6Label: 'H6',
|
|
307
287
|
};
|
|
308
|
-
|
|
288
|
+
// ─── Abstract Base ────────────────────────────────────────────────────────────
|
|
289
|
+
/**
|
|
290
|
+
* Abstract base class shared by StackchRichtextEditor (core) and
|
|
291
|
+
* StackchRichtextEditorMaterial (Material variant).
|
|
292
|
+
* Contains all editing logic; concrete subclasses add only the @Component
|
|
293
|
+
* decorator with their own template / styles / toolbar.
|
|
294
|
+
*/
|
|
295
|
+
class StackchRichtextEditorBase {
|
|
309
296
|
cdr;
|
|
297
|
+
// Override in concrete class to distinguish log output
|
|
298
|
+
logPrefix = '[RTE]';
|
|
310
299
|
placeholder = '';
|
|
311
300
|
showToolbar = true;
|
|
312
301
|
fonts = [
|
|
@@ -326,7 +315,6 @@ class StackchRichtextEditor {
|
|
|
326
315
|
get disabled() { return this._disabled; }
|
|
327
316
|
_disabled = false;
|
|
328
317
|
valueChange = new EventEmitter();
|
|
329
|
-
// Structured metrics event (future-proof)
|
|
330
318
|
metricsChange = new EventEmitter();
|
|
331
319
|
editorRef;
|
|
332
320
|
constructor(cdr) {
|
|
@@ -362,7 +350,7 @@ class StackchRichtextEditor {
|
|
|
362
350
|
isBoldActive = false;
|
|
363
351
|
isItalicActive = false;
|
|
364
352
|
isUnderlineActive = false;
|
|
365
|
-
// Selection helpers
|
|
353
|
+
// ─── Selection helpers ───────────────────────────────────────────────────
|
|
366
354
|
saveSelection() {
|
|
367
355
|
const sel = window.getSelection();
|
|
368
356
|
if (!sel || sel.rangeCount === 0)
|
|
@@ -375,7 +363,6 @@ class StackchRichtextEditor {
|
|
|
375
363
|
}
|
|
376
364
|
// Prevent toolbar buttons from stealing focus from the editor while preserving selection
|
|
377
365
|
onToolbarMouseDown(evt) {
|
|
378
|
-
// Keep focus on the editor to avoid persistent button focus outlines
|
|
379
366
|
evt.preventDefault();
|
|
380
367
|
evt.stopPropagation();
|
|
381
368
|
this.saveSelection();
|
|
@@ -401,6 +388,7 @@ class StackchRichtextEditor {
|
|
|
401
388
|
const node = container.nodeType === Node.ELEMENT_NODE ? container : container.parentElement;
|
|
402
389
|
return !!node && editor.contains(node);
|
|
403
390
|
}
|
|
391
|
+
// ─── Host listeners ──────────────────────────────────────────────────────
|
|
404
392
|
// Update active-state on selection changes inside the editor
|
|
405
393
|
onSelectionChange() {
|
|
406
394
|
const sel = window.getSelection();
|
|
@@ -424,7 +412,7 @@ class StackchRichtextEditor {
|
|
|
424
412
|
}
|
|
425
413
|
// Keyboard: Undo/Redo
|
|
426
414
|
onKeydown(evt) {
|
|
427
|
-
const isMac = navigator.platform.toLowerCase().includes('mac');
|
|
415
|
+
const isMac = (navigator.userAgentData?.platform ?? navigator.platform).toLowerCase().includes('mac');
|
|
428
416
|
const mod = isMac ? evt.metaKey : evt.ctrlKey;
|
|
429
417
|
if (mod && !evt.shiftKey && (evt.key === 'z' || evt.key === 'Z')) {
|
|
430
418
|
evt.preventDefault();
|
|
@@ -435,6 +423,7 @@ class StackchRichtextEditor {
|
|
|
435
423
|
this.redo();
|
|
436
424
|
}
|
|
437
425
|
}
|
|
426
|
+
// ─── Menu toggles ────────────────────────────────────────────────────────
|
|
438
427
|
toggleFontMenu(evt) {
|
|
439
428
|
this.saveSelection();
|
|
440
429
|
this.showFontMenu = !this.showFontMenu;
|
|
@@ -452,7 +441,6 @@ class StackchRichtextEditor {
|
|
|
452
441
|
toggleFontPanel(evt) {
|
|
453
442
|
this.saveSelection();
|
|
454
443
|
this.showFontPanel = !this.showFontPanel;
|
|
455
|
-
// close others if open
|
|
456
444
|
if (this.showFontPanel) {
|
|
457
445
|
this.showFontMenu = false;
|
|
458
446
|
this.showSizeMenu = false;
|
|
@@ -531,6 +519,7 @@ class StackchRichtextEditor {
|
|
|
531
519
|
}
|
|
532
520
|
evt.stopPropagation();
|
|
533
521
|
}
|
|
522
|
+
// ─── Pick handlers (toolbar → editor) ───────────────────────────────────
|
|
534
523
|
onPickAlign(where) {
|
|
535
524
|
this.focusEditor();
|
|
536
525
|
this.restoreSelection();
|
|
@@ -583,7 +572,7 @@ class StackchRichtextEditor {
|
|
|
583
572
|
this.emitValue();
|
|
584
573
|
this.takeSnapshot('spacing');
|
|
585
574
|
}
|
|
586
|
-
// ControlValueAccessor
|
|
575
|
+
// ─── ControlValueAccessor ────────────────────────────────────────────────
|
|
587
576
|
writeValue(value) {
|
|
588
577
|
const el = this.editorRef?.nativeElement;
|
|
589
578
|
if (!el)
|
|
@@ -599,12 +588,11 @@ class StackchRichtextEditor {
|
|
|
599
588
|
registerOnChange(fn) { this.onChange = fn; }
|
|
600
589
|
registerOnTouched(fn) { this.onTouched = fn; }
|
|
601
590
|
setDisabledState(isDisabled) { this.disabled = isDisabled; }
|
|
591
|
+
// ─── Toolbar actions ─────────────────────────────────────────────────────
|
|
602
592
|
// Toolbar actions using document.execCommand (deprecated but broadly supported)
|
|
603
593
|
cmd(command, value) {
|
|
604
|
-
// Restore last selection from editor before applying an action triggered by toolbar
|
|
605
594
|
this.focusEditor();
|
|
606
595
|
this.restoreSelection();
|
|
607
|
-
// Bevorzugt: eigene Range-basierte Implementierungen
|
|
608
596
|
switch (command) {
|
|
609
597
|
case 'bold':
|
|
610
598
|
this.applyInlineStyleSmart('fontWeight', 'bold');
|
|
@@ -669,7 +657,6 @@ class StackchRichtextEditor {
|
|
|
669
657
|
}
|
|
670
658
|
// Fallback (deprecated): nur für Format entfernen / Links lösen als Übergang
|
|
671
659
|
try {
|
|
672
|
-
// Hinweis im Dev-Mode ausgeben
|
|
673
660
|
if (!('___rteWarned' in this)) {
|
|
674
661
|
console.warn('[richtext-editor] document.execCommand ist deprecated; Fallback wird nur für removeFormat/unlink verwendet.');
|
|
675
662
|
this.___rteWarned = true;
|
|
@@ -705,7 +692,6 @@ class StackchRichtextEditor {
|
|
|
705
692
|
return;
|
|
706
693
|
const r = sel.getRangeAt(0);
|
|
707
694
|
if (r.collapsed) {
|
|
708
|
-
// Firefox/Edge: wenn keine explizite Auswahl, erweitere auf nächstes Wort
|
|
709
695
|
this.expandRangeToWord(r);
|
|
710
696
|
}
|
|
711
697
|
this.applySelectionStyles({ color });
|
|
@@ -729,7 +715,6 @@ class StackchRichtextEditor {
|
|
|
729
715
|
const editor = this.editorRef.nativeElement;
|
|
730
716
|
let node = range.startContainer;
|
|
731
717
|
if (node.nodeType !== Node.TEXT_NODE) {
|
|
732
|
-
// Versuche, einen Textknoten in der Nähe zu finden
|
|
733
718
|
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT);
|
|
734
719
|
let found = null;
|
|
735
720
|
while (walker.nextNode()) {
|
|
@@ -744,7 +729,6 @@ class StackchRichtextEditor {
|
|
|
744
729
|
}
|
|
745
730
|
const text = node.nodeType === Node.TEXT_NODE ? node.data : '';
|
|
746
731
|
let start = 0, end = text.length;
|
|
747
|
-
// einfache Wortgrenzen-Heuristik
|
|
748
732
|
const pos = range.startOffset;
|
|
749
733
|
for (let i = pos; i > 0; i--) {
|
|
750
734
|
if (/\s/.test(text[i - 1])) {
|
|
@@ -788,7 +772,6 @@ class StackchRichtextEditor {
|
|
|
788
772
|
this.updateInlineStates();
|
|
789
773
|
}
|
|
790
774
|
onPaste(evt) {
|
|
791
|
-
// Optional: Clean paste to plain text while keeping basic formatting minimal.
|
|
792
775
|
if (!evt.clipboardData)
|
|
793
776
|
return;
|
|
794
777
|
evt.preventDefault();
|
|
@@ -797,8 +780,8 @@ class StackchRichtextEditor {
|
|
|
797
780
|
this.emitValue();
|
|
798
781
|
this.takeSnapshot('paste');
|
|
799
782
|
}
|
|
783
|
+
// ─── Internal emit helpers ───────────────────────────────────────────────
|
|
800
784
|
emitValue() {
|
|
801
|
-
// Clean up empty style attributes and redundant spans before emitting
|
|
802
785
|
this.cleanupEmptyStylesAndSpans();
|
|
803
786
|
const val = this.editorRef.nativeElement.innerHTML;
|
|
804
787
|
this.onChange(val);
|
|
@@ -811,14 +794,12 @@ class StackchRichtextEditor {
|
|
|
811
794
|
if (!editor)
|
|
812
795
|
return;
|
|
813
796
|
const htmlLen = editor.innerHTML.length;
|
|
814
|
-
// textContent excludes markup; normalize null to empty string
|
|
815
797
|
const textLen = (editor.textContent || '').length;
|
|
816
|
-
// Structured metrics event
|
|
817
798
|
this.metricsChange.emit({ htmlLength: htmlLen, textLength: textLen });
|
|
818
799
|
}
|
|
819
800
|
// Remove empty style attributes (style="") and unwrap spans without any attributes
|
|
820
801
|
cleanupEmptyStylesAndSpans(root) {
|
|
821
|
-
console.log(
|
|
802
|
+
console.log(`${this.logPrefix} cleanupEmptyStylesAndSpans: start cleanup`);
|
|
822
803
|
const editor = root || this.editorRef.nativeElement;
|
|
823
804
|
const toUnwrap = [];
|
|
824
805
|
const toRemove = [];
|
|
@@ -826,7 +807,6 @@ class StackchRichtextEditor {
|
|
|
826
807
|
while (walker.nextNode()) {
|
|
827
808
|
const el = walker.currentNode;
|
|
828
809
|
if (el.hasAttribute('style')) {
|
|
829
|
-
// If no style declarations remain, drop the attribute
|
|
830
810
|
const cssText = el.getAttribute('style') || '';
|
|
831
811
|
const byApiEmpty = (el.style ? el.style.length === 0 : false);
|
|
832
812
|
const normalized = cssText.replace(/[\s;]/g, '');
|
|
@@ -836,28 +816,28 @@ class StackchRichtextEditor {
|
|
|
836
816
|
}
|
|
837
817
|
if (el.tagName === 'SPAN') {
|
|
838
818
|
if (!el.firstChild) {
|
|
839
|
-
console.log(
|
|
819
|
+
console.log(`${this.logPrefix} cleanup: removing empty span`, el);
|
|
840
820
|
toRemove.push(el);
|
|
841
821
|
continue;
|
|
842
822
|
}
|
|
843
823
|
if (el.attributes.length === 0) {
|
|
844
|
-
console.log(
|
|
824
|
+
console.log(`${this.logPrefix} cleanup: unwrapping style-free span`, el);
|
|
845
825
|
toUnwrap.push(el);
|
|
846
826
|
}
|
|
847
827
|
}
|
|
848
828
|
}
|
|
849
829
|
for (const span of toUnwrap) {
|
|
850
|
-
console.log(
|
|
830
|
+
console.log(`${this.logPrefix} cleanup: unwrap span`, { span, childCount: span.childNodes.length });
|
|
851
831
|
while (span.firstChild)
|
|
852
832
|
span.parentNode?.insertBefore(span.firstChild, span);
|
|
853
833
|
span.remove();
|
|
854
834
|
}
|
|
855
835
|
for (const span of toRemove) {
|
|
856
|
-
console.log(
|
|
836
|
+
console.log(`${this.logPrefix} cleanup: remove span without children`, span);
|
|
857
837
|
span.remove();
|
|
858
838
|
}
|
|
859
839
|
}
|
|
860
|
-
// History API
|
|
840
|
+
// ─── History API ─────────────────────────────────────────────────────────
|
|
861
841
|
get canUndo() { return this.historyIndex > 0; }
|
|
862
842
|
get canRedo() { return this.historyIndex >= 0 && this.historyIndex < this.history.length - 1; }
|
|
863
843
|
undo() {
|
|
@@ -919,12 +899,10 @@ class StackchRichtextEditor {
|
|
|
919
899
|
const editor = this.editorRef.nativeElement;
|
|
920
900
|
this.isRestoringHistory = true;
|
|
921
901
|
editor.innerHTML = snap.html;
|
|
922
|
-
// Selektion wiederherstellen
|
|
923
902
|
if (snap.range) {
|
|
924
903
|
this.restoreSerializedRange(snap.range);
|
|
925
904
|
}
|
|
926
905
|
else {
|
|
927
|
-
// Cursor ans Ende
|
|
928
906
|
const sel = window.getSelection();
|
|
929
907
|
if (sel) {
|
|
930
908
|
sel.removeAllRanges();
|
|
@@ -936,7 +914,6 @@ class StackchRichtextEditor {
|
|
|
936
914
|
}
|
|
937
915
|
this.historyIndex = index;
|
|
938
916
|
this.isRestoringHistory = false;
|
|
939
|
-
// Werte emittieren nach Restore
|
|
940
917
|
this.emitValue();
|
|
941
918
|
}
|
|
942
919
|
serializeRange(range) {
|
|
@@ -1010,13 +987,11 @@ class StackchRichtextEditor {
|
|
|
1010
987
|
el.focus();
|
|
1011
988
|
}
|
|
1012
989
|
}
|
|
1013
|
-
//
|
|
990
|
+
// ─── Inline style application ────────────────────────────────────────────
|
|
1014
991
|
applyInlineStyle(cssProp, value) {
|
|
1015
|
-
// Delegate to generic, style-agnostic applier
|
|
1016
992
|
this.applySelectionStyles({ [cssProp]: value });
|
|
1017
993
|
}
|
|
1018
994
|
applyInlineStyleSmart(cssProp, value) {
|
|
1019
|
-
// Delegate to generic applier which handles selection/logging
|
|
1020
995
|
this.applySelectionStyles({ [cssProp]: value });
|
|
1021
996
|
}
|
|
1022
997
|
applySelectionStyles(styles) {
|
|
@@ -1024,21 +999,21 @@ class StackchRichtextEditor {
|
|
|
1024
999
|
this.restoreSelection();
|
|
1025
1000
|
const sel = window.getSelection();
|
|
1026
1001
|
if (!sel || sel.rangeCount === 0) {
|
|
1027
|
-
console.warn(
|
|
1002
|
+
console.warn(`${this.logPrefix} applySelectionStyles: no selection available`, { styles });
|
|
1028
1003
|
return;
|
|
1029
1004
|
}
|
|
1030
1005
|
let range = sel.getRangeAt(0);
|
|
1031
1006
|
if (range.collapsed) {
|
|
1032
|
-
console.warn(
|
|
1007
|
+
console.warn(`${this.logPrefix} applySelectionStyles: range is collapsed`, { styles });
|
|
1033
1008
|
return;
|
|
1034
1009
|
}
|
|
1035
1010
|
const entries = Object.entries(styles).filter(([, v]) => v != null && v !== '');
|
|
1036
1011
|
if (entries.length === 0) {
|
|
1037
|
-
console.warn(
|
|
1012
|
+
console.warn(`${this.logPrefix} applySelectionStyles: no style entries to apply`, { styles });
|
|
1038
1013
|
return;
|
|
1039
1014
|
}
|
|
1040
1015
|
const propsToClear = Array.from(new Set(entries.map(([prop]) => this.toCssProperty(prop))));
|
|
1041
|
-
console.log(
|
|
1016
|
+
console.log(`${this.logPrefix} applySelectionStyles: clearing props before apply`, { propsToClear, entries });
|
|
1042
1017
|
for (const cssProp of propsToClear) {
|
|
1043
1018
|
const beforeClear = range.cloneRange();
|
|
1044
1019
|
const clearedRange = this.removeInlineStyleInRange(range, cssProp, { suppressEmit: true });
|
|
@@ -1050,24 +1025,24 @@ class StackchRichtextEditor {
|
|
|
1050
1025
|
range = clearedRange;
|
|
1051
1026
|
}
|
|
1052
1027
|
if (range.collapsed && !beforeClear.collapsed) {
|
|
1053
|
-
console.warn(
|
|
1054
|
-
const
|
|
1055
|
-
if (
|
|
1056
|
-
|
|
1057
|
-
|
|
1028
|
+
console.warn(`${this.logPrefix} applySelectionStyles: range collapsed after clearing, restoring previous range`);
|
|
1029
|
+
const sel2 = window.getSelection();
|
|
1030
|
+
if (sel2) {
|
|
1031
|
+
sel2.removeAllRanges();
|
|
1032
|
+
sel2.addRange(beforeClear);
|
|
1058
1033
|
}
|
|
1059
1034
|
range = beforeClear;
|
|
1060
1035
|
}
|
|
1061
1036
|
}
|
|
1062
1037
|
const segments = this.collectTextSegments(range);
|
|
1063
1038
|
if (segments.length === 0) {
|
|
1064
|
-
console.warn(
|
|
1039
|
+
console.warn(`${this.logPrefix} applySelectionStyles: no text segments found`, {
|
|
1065
1040
|
entries,
|
|
1066
1041
|
commonAncestor: range.commonAncestorContainer
|
|
1067
1042
|
});
|
|
1068
1043
|
return;
|
|
1069
1044
|
}
|
|
1070
|
-
console.log(
|
|
1045
|
+
console.log(`${this.logPrefix} applySelectionStyles: applying styles to segments`, {
|
|
1071
1046
|
entries,
|
|
1072
1047
|
segmentCount: segments.length
|
|
1073
1048
|
});
|
|
@@ -1140,7 +1115,7 @@ class StackchRichtextEditor {
|
|
|
1140
1115
|
return this.mergeAdjacentStyledSpans(wrapper);
|
|
1141
1116
|
}
|
|
1142
1117
|
catch (err) {
|
|
1143
|
-
console.error(
|
|
1118
|
+
console.error(`${this.logPrefix} applyStylesToSegment: failed to surround contents`, {
|
|
1144
1119
|
error: err,
|
|
1145
1120
|
segment,
|
|
1146
1121
|
entries
|
|
@@ -1206,7 +1181,6 @@ class StackchRichtextEditor {
|
|
|
1206
1181
|
const frag = range.extractContents();
|
|
1207
1182
|
el.appendChild(frag);
|
|
1208
1183
|
range.insertNode(el);
|
|
1209
|
-
// Auswahl hinter das Element setzen
|
|
1210
1184
|
sel.removeAllRanges();
|
|
1211
1185
|
const after = document.createRange();
|
|
1212
1186
|
after.setStartAfter(el);
|
|
@@ -1221,14 +1195,13 @@ class StackchRichtextEditor {
|
|
|
1221
1195
|
range.deleteContents();
|
|
1222
1196
|
const node = document.createTextNode(text);
|
|
1223
1197
|
range.insertNode(node);
|
|
1224
|
-
// Cursor ans Ende des eingefügten Textes
|
|
1225
1198
|
sel.removeAllRanges();
|
|
1226
1199
|
const after = document.createRange();
|
|
1227
1200
|
after.setStartAfter(node);
|
|
1228
1201
|
after.collapse(true);
|
|
1229
1202
|
sel.addRange(after);
|
|
1230
1203
|
}
|
|
1231
|
-
//
|
|
1204
|
+
// ─── Inline toggle logic (Bold / Italic / Underline) ─────────────────────
|
|
1232
1205
|
updateInlineStates() {
|
|
1233
1206
|
const sel = window.getSelection();
|
|
1234
1207
|
if (!sel || sel.rangeCount === 0) {
|
|
@@ -1250,7 +1223,6 @@ class StackchRichtextEditor {
|
|
|
1250
1223
|
this.isBoldActive = this.computeBoldAnyForRange(range);
|
|
1251
1224
|
this.isItalicActive = this.computeItalicAnyForRange(range);
|
|
1252
1225
|
this.isUnderlineActive = this.computeUnderlineAnyForRange(range);
|
|
1253
|
-
// ensure UI reflects changes immediately
|
|
1254
1226
|
try {
|
|
1255
1227
|
this.cdr.detectChanges();
|
|
1256
1228
|
}
|
|
@@ -1323,13 +1295,12 @@ class StackchRichtextEditor {
|
|
|
1323
1295
|
}
|
|
1324
1296
|
};
|
|
1325
1297
|
const matchesEl = (el) => this.isStyleCarrier(el, cssPropKebab);
|
|
1326
|
-
console.log(
|
|
1298
|
+
console.log(`${this.logPrefix} removeInlineStyleInRange:start`, {
|
|
1327
1299
|
cssPropKebab,
|
|
1328
1300
|
rangeCollapsed: effectiveRange.collapsed,
|
|
1329
1301
|
commonTag: common.tagName,
|
|
1330
1302
|
commonHasStyle: common.style ? common.style.getPropertyValue?.(cssPropKebab) : undefined
|
|
1331
1303
|
});
|
|
1332
|
-
// Include the common element itself if it matches and intersects (TreeWalker won't visit the root)
|
|
1333
1304
|
if (common instanceof HTMLElement && matchesEl(common) && intersects(common)) {
|
|
1334
1305
|
affected.push(common);
|
|
1335
1306
|
}
|
|
@@ -1340,45 +1311,45 @@ class StackchRichtextEditor {
|
|
|
1340
1311
|
continue;
|
|
1341
1312
|
if (intersects(el)) {
|
|
1342
1313
|
affected.push(el);
|
|
1343
|
-
console.log(
|
|
1314
|
+
console.log(`${this.logPrefix} removeInlineStyleInRange:match`, el.tagName, el.getAttribute('style'));
|
|
1344
1315
|
}
|
|
1345
1316
|
}
|
|
1346
1317
|
let removedTags = 0;
|
|
1347
1318
|
let removedProps = 0;
|
|
1348
1319
|
for (const el of affected) {
|
|
1349
1320
|
if (el.tagName === 'B' || el.tagName === 'STRONG' || el.tagName === 'I' || el.tagName === 'EM' || el.tagName === 'U') {
|
|
1350
|
-
console.log(
|
|
1321
|
+
console.log(`${this.logPrefix} unwrap tag`, el.tagName);
|
|
1351
1322
|
while (el.firstChild)
|
|
1352
1323
|
el.parentNode?.insertBefore(el.firstChild, el);
|
|
1353
1324
|
el.remove();
|
|
1354
1325
|
removedTags++;
|
|
1355
1326
|
continue;
|
|
1356
1327
|
}
|
|
1357
|
-
console.log(
|
|
1328
|
+
console.log(`${this.logPrefix} remove style`, cssPropKebab, 'from', el.tagName, el.getAttribute('style'));
|
|
1358
1329
|
el.style.removeProperty(cssPropKebab);
|
|
1359
1330
|
if (!el.style.length) {
|
|
1360
|
-
console.log(
|
|
1331
|
+
console.log(`${this.logPrefix} removeInlineStyleInRange: style attribute now empty, removing attribute`, el);
|
|
1361
1332
|
el.removeAttribute('style');
|
|
1362
1333
|
}
|
|
1363
1334
|
removedProps++;
|
|
1364
1335
|
if (!el.getAttribute('style')) {
|
|
1365
|
-
console.log(
|
|
1336
|
+
console.log(`${this.logPrefix} unwrap empty styled span`, el.tagName);
|
|
1366
1337
|
while (el.firstChild)
|
|
1367
1338
|
el.parentNode?.insertBefore(el.firstChild, el);
|
|
1368
1339
|
el.remove();
|
|
1369
1340
|
}
|
|
1370
1341
|
}
|
|
1371
1342
|
this.pruneDanglingStyleCarriers(common, cssPropKebab);
|
|
1372
|
-
console.log(
|
|
1343
|
+
console.log(`${this.logPrefix} removeInlineStyleInRange:done`, { affected: affected.length, removedTags, removedProps });
|
|
1373
1344
|
let resultRange = null;
|
|
1374
1345
|
if (!options?.suppressEmit) {
|
|
1375
1346
|
this.emitValue();
|
|
1376
1347
|
resultRange = null;
|
|
1377
1348
|
}
|
|
1378
1349
|
else {
|
|
1379
|
-
const
|
|
1380
|
-
if (
|
|
1381
|
-
resultRange =
|
|
1350
|
+
const sel2 = window.getSelection();
|
|
1351
|
+
if (sel2 && sel2.rangeCount > 0) {
|
|
1352
|
+
resultRange = sel2.getRangeAt(0).cloneRange();
|
|
1382
1353
|
}
|
|
1383
1354
|
else if (shouldRestoreSelection) {
|
|
1384
1355
|
resultRange = effectiveRange.cloneRange();
|
|
@@ -1409,11 +1380,7 @@ class StackchRichtextEditor {
|
|
|
1409
1380
|
toRemove.push(el);
|
|
1410
1381
|
}
|
|
1411
1382
|
for (const el of toRemove) {
|
|
1412
|
-
console.log(
|
|
1413
|
-
if (el.tagName === 'B' || el.tagName === 'STRONG' || el.tagName === 'I' || el.tagName === 'EM' || el.tagName === 'U') {
|
|
1414
|
-
el.remove();
|
|
1415
|
-
continue;
|
|
1416
|
-
}
|
|
1383
|
+
console.log(`${this.logPrefix} pruneDanglingStyleCarriers: removing empty carrier`, { tag: el.tagName, style: el.getAttribute('style') });
|
|
1417
1384
|
el.remove();
|
|
1418
1385
|
}
|
|
1419
1386
|
}
|
|
@@ -1558,7 +1525,7 @@ class StackchRichtextEditor {
|
|
|
1558
1525
|
if (range.collapsed)
|
|
1559
1526
|
this.expandRangeToWord(range);
|
|
1560
1527
|
const anyActive = this.computeBoldAnyForRange(range);
|
|
1561
|
-
console.log(
|
|
1528
|
+
console.log(`${this.logPrefix} toggleBold`, { anyActive, rangeCollapsed: range.collapsed });
|
|
1562
1529
|
if (anyActive) {
|
|
1563
1530
|
this.removeInlineStyleInRange(range, 'font-weight');
|
|
1564
1531
|
}
|
|
@@ -1606,6 +1573,7 @@ class StackchRichtextEditor {
|
|
|
1606
1573
|
this.updateInlineStates();
|
|
1607
1574
|
this.takeSnapshot('toggle-underline');
|
|
1608
1575
|
}
|
|
1576
|
+
// ─── Block operations ─────────────────────────────────────────────────────
|
|
1609
1577
|
getCurrentRange() {
|
|
1610
1578
|
const sel = window.getSelection();
|
|
1611
1579
|
if (!sel || sel.rangeCount === 0)
|
|
@@ -1619,7 +1587,6 @@ class StackchRichtextEditor {
|
|
|
1619
1587
|
while (el && el.parentElement && el.parentElement !== editor) {
|
|
1620
1588
|
el = el.parentElement;
|
|
1621
1589
|
}
|
|
1622
|
-
// Wenn direktes Kind des Editors
|
|
1623
1590
|
if (el && el.parentElement === editor)
|
|
1624
1591
|
return el;
|
|
1625
1592
|
return editor;
|
|
@@ -1638,34 +1605,29 @@ class StackchRichtextEditor {
|
|
|
1638
1605
|
if (!range)
|
|
1639
1606
|
return;
|
|
1640
1607
|
const editor = this.editorRef.nativeElement;
|
|
1641
|
-
// Wenn bereits in einer Liste, Liste aufheben
|
|
1642
1608
|
const listAncestor = this.findClosest(range.commonAncestorContainer, 'ul,ol');
|
|
1643
1609
|
if (listAncestor) {
|
|
1644
|
-
// unwrap: li-Inhalte an die Stelle der Liste setzen
|
|
1645
1610
|
const frag = document.createDocumentFragment();
|
|
1646
|
-
const items = Array.from(listAncestor.children);
|
|
1611
|
+
const items = Array.from(listAncestor.children);
|
|
1647
1612
|
for (const li of items) {
|
|
1648
1613
|
while (li.firstChild)
|
|
1649
1614
|
frag.appendChild(li.firstChild);
|
|
1650
|
-
// Optional: Zeilenumbruch zwischen Items
|
|
1651
1615
|
frag.appendChild(document.createElement('br'));
|
|
1652
1616
|
}
|
|
1653
1617
|
listAncestor.replaceWith(frag);
|
|
1654
1618
|
return;
|
|
1655
1619
|
}
|
|
1656
|
-
// Neue Liste um die aktuelle Auswahl legen
|
|
1657
1620
|
const list = document.createElement(kind);
|
|
1658
1621
|
const li = document.createElement('li');
|
|
1659
1622
|
const contents = range.extractContents();
|
|
1660
1623
|
if (!contents.hasChildNodes()) {
|
|
1661
|
-
li.textContent = '\u200b';
|
|
1624
|
+
li.textContent = '\u200b';
|
|
1662
1625
|
}
|
|
1663
1626
|
else {
|
|
1664
1627
|
li.appendChild(contents);
|
|
1665
1628
|
}
|
|
1666
1629
|
list.appendChild(li);
|
|
1667
1630
|
range.insertNode(list);
|
|
1668
|
-
// Cursor ins li setzen
|
|
1669
1631
|
const sel = window.getSelection();
|
|
1670
1632
|
if (sel) {
|
|
1671
1633
|
sel.removeAllRanges();
|
|
@@ -1691,7 +1653,6 @@ class StackchRichtextEditor {
|
|
|
1691
1653
|
applyAlign(startBlock);
|
|
1692
1654
|
}
|
|
1693
1655
|
else {
|
|
1694
|
-
// grob: alle direkten Kinder zwischen start und end ausrichten
|
|
1695
1656
|
const children = Array.from(editor.children);
|
|
1696
1657
|
const i1 = children.indexOf(startBlock);
|
|
1697
1658
|
const i2 = children.indexOf(endBlock);
|
|
@@ -1745,8 +1706,8 @@ class StackchRichtextEditor {
|
|
|
1745
1706
|
}
|
|
1746
1707
|
}
|
|
1747
1708
|
}
|
|
1748
|
-
// Versucht, Margin/Padding auf die konkrete Text-Selektion anzuwenden
|
|
1749
|
-
// Liefert true, wenn inline angewendet werden konnte; sonst false
|
|
1709
|
+
// Versucht, Margin/Padding auf die konkrete Text-Selektion anzuwenden (inline Wrapper).
|
|
1710
|
+
// Liefert true, wenn inline angewendet werden konnte; sonst false.
|
|
1750
1711
|
applySpacingToSelection(kind, target, value) {
|
|
1751
1712
|
const sel = window.getSelection();
|
|
1752
1713
|
if (!sel || sel.rangeCount === 0)
|
|
@@ -1756,7 +1717,6 @@ class StackchRichtextEditor {
|
|
|
1756
1717
|
return false;
|
|
1757
1718
|
const startBlock = this.getEditorChildAncestor(range.startContainer);
|
|
1758
1719
|
const endBlock = this.getEditorChildAncestor(range.endContainer);
|
|
1759
|
-
// Nur inline, wenn innerhalb desselben Blocks
|
|
1760
1720
|
if (!startBlock || !endBlock || startBlock !== endBlock)
|
|
1761
1721
|
return false;
|
|
1762
1722
|
const wrapper = document.createElement('span');
|
|
@@ -1772,15 +1732,12 @@ class StackchRichtextEditor {
|
|
|
1772
1732
|
wrapper.style[`${kind}Left`] = px;
|
|
1773
1733
|
wrapper.style[`${kind}Right`] = px;
|
|
1774
1734
|
}
|
|
1775
|
-
// Für vertikale Margins auf Inline-Elementen sicherstellen, dass sie greifen
|
|
1776
1735
|
if (kind === 'margin' && (target === 'all' || target === 'vertical')) {
|
|
1777
1736
|
wrapper.style.display = 'inline-block';
|
|
1778
1737
|
}
|
|
1779
|
-
// Auswahl extrahieren und in Wrapper einsetzen
|
|
1780
1738
|
const frag = range.extractContents();
|
|
1781
1739
|
wrapper.appendChild(frag);
|
|
1782
1740
|
range.insertNode(wrapper);
|
|
1783
|
-
// Gleichartige Wrapper zusammenführen und Cursor korrekt setzen
|
|
1784
1741
|
const normalized = this.normalizeSpacingSpans(wrapper, kind, target, value) || wrapper;
|
|
1785
1742
|
sel.removeAllRanges();
|
|
1786
1743
|
const after = document.createRange();
|
|
@@ -1788,7 +1745,6 @@ class StackchRichtextEditor {
|
|
|
1788
1745
|
after.setStartAfter(normalized);
|
|
1789
1746
|
}
|
|
1790
1747
|
else {
|
|
1791
|
-
// Fallback: an das Ende des Startblocks
|
|
1792
1748
|
const sb = this.getEditorChildAncestor(range.startContainer);
|
|
1793
1749
|
if (sb)
|
|
1794
1750
|
after.selectNodeContents(sb);
|
|
@@ -1797,7 +1753,7 @@ class StackchRichtextEditor {
|
|
|
1797
1753
|
sel.addRange(after);
|
|
1798
1754
|
return true;
|
|
1799
1755
|
}
|
|
1800
|
-
normalizeSpacingSpans(span, kind, target,
|
|
1756
|
+
normalizeSpacingSpans(span, kind, target, _value) {
|
|
1801
1757
|
const props = [];
|
|
1802
1758
|
if (target === 'all')
|
|
1803
1759
|
props.push(kind);
|
|
@@ -1806,7 +1762,6 @@ class StackchRichtextEditor {
|
|
|
1806
1762
|
if (target === 'horizontal')
|
|
1807
1763
|
props.push(`${kind}Left`, `${kind}Right`);
|
|
1808
1764
|
const displayNeeded = kind === 'margin' && (target === 'all' || target === 'vertical');
|
|
1809
|
-
const v = `${value}px`;
|
|
1810
1765
|
const hasSameSpacing = (a, b) => {
|
|
1811
1766
|
for (const p of props) {
|
|
1812
1767
|
if (a.style[p] !== b.style[p])
|
|
@@ -1818,7 +1773,6 @@ class StackchRichtextEditor {
|
|
|
1818
1773
|
}
|
|
1819
1774
|
return true;
|
|
1820
1775
|
};
|
|
1821
|
-
// Downward: verschachtelte identische Spans in span zusammenführen
|
|
1822
1776
|
if (span.children.length === 1) {
|
|
1823
1777
|
const only = span.children[0];
|
|
1824
1778
|
if (only && only.tagName === 'SPAN' && hasSameSpacing(span, only)) {
|
|
@@ -1828,7 +1782,6 @@ class StackchRichtextEditor {
|
|
|
1828
1782
|
}
|
|
1829
1783
|
}
|
|
1830
1784
|
let current = span;
|
|
1831
|
-
// Upward: mit Elternelement verschmelzen, wenn identischer Span
|
|
1832
1785
|
const parent = current.parentElement;
|
|
1833
1786
|
if (parent && parent.tagName === 'SPAN' && hasSameSpacing(parent, current)) {
|
|
1834
1787
|
while (current.firstChild)
|
|
@@ -1838,7 +1791,6 @@ class StackchRichtextEditor {
|
|
|
1838
1791
|
}
|
|
1839
1792
|
if (!current)
|
|
1840
1793
|
return null;
|
|
1841
|
-
// Left merge: vorherige Geschwister-Spans mit gleicher Formatierung in current ziehen
|
|
1842
1794
|
let prev = current.previousElementSibling;
|
|
1843
1795
|
if (prev && prev.tagName === 'SPAN' && hasSameSpacing(prev, current)) {
|
|
1844
1796
|
while (current.firstChild)
|
|
@@ -1846,7 +1798,6 @@ class StackchRichtextEditor {
|
|
|
1846
1798
|
current.remove();
|
|
1847
1799
|
current = prev;
|
|
1848
1800
|
}
|
|
1849
|
-
// Right merge: folgende Geschwister-Spans in current ziehen
|
|
1850
1801
|
let next = current.nextElementSibling;
|
|
1851
1802
|
while (next && next.tagName === 'SPAN' && hasSameSpacing(current, next)) {
|
|
1852
1803
|
while (next.firstChild)
|
|
@@ -1862,6 +1813,7 @@ class StackchRichtextEditor {
|
|
|
1862
1813
|
if (!range)
|
|
1863
1814
|
return;
|
|
1864
1815
|
const editor = this.editorRef.nativeElement;
|
|
1816
|
+
const PRE_STYLE = 'white-space: pre-wrap; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;';
|
|
1865
1817
|
const replaceTag = (el, newTag) => {
|
|
1866
1818
|
if (!el || el === editor)
|
|
1867
1819
|
return null;
|
|
@@ -1873,24 +1825,23 @@ class StackchRichtextEditor {
|
|
|
1873
1825
|
};
|
|
1874
1826
|
const startBlock = this.getEditorChildAncestor(range.startContainer);
|
|
1875
1827
|
const endBlock = this.getEditorChildAncestor(range.endContainer);
|
|
1876
|
-
if (startBlock && startBlock !== editor &&
|
|
1828
|
+
if (startBlock && startBlock !== editor && startBlock === endBlock) {
|
|
1877
1829
|
const currentTag = (startBlock.tagName || '').toLowerCase();
|
|
1878
1830
|
if (currentTag === tag)
|
|
1879
1831
|
return;
|
|
1880
1832
|
const convertible = /^(p|div|pre|h1|h2|h3|h4|h5|h6)$/i.test(currentTag);
|
|
1881
1833
|
if (convertible) {
|
|
1882
1834
|
const neo = replaceTag(startBlock, tag);
|
|
1883
|
-
if (neo && tag === 'pre')
|
|
1884
|
-
neo.setAttribute('style',
|
|
1885
|
-
}
|
|
1835
|
+
if (neo && tag === 'pre')
|
|
1836
|
+
neo.setAttribute('style', PRE_STYLE);
|
|
1886
1837
|
if (neo) {
|
|
1887
1838
|
const sel = window.getSelection();
|
|
1888
1839
|
if (sel) {
|
|
1889
1840
|
sel.removeAllRanges();
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
sel.addRange(
|
|
1841
|
+
const r = document.createRange();
|
|
1842
|
+
r.selectNodeContents(neo);
|
|
1843
|
+
r.collapse(false);
|
|
1844
|
+
sel.addRange(r);
|
|
1894
1845
|
}
|
|
1895
1846
|
}
|
|
1896
1847
|
return;
|
|
@@ -1905,12 +1856,10 @@ class StackchRichtextEditor {
|
|
|
1905
1856
|
let last = null;
|
|
1906
1857
|
for (let i = from; i <= to; i++) {
|
|
1907
1858
|
const el = children[i];
|
|
1908
|
-
|
|
1909
|
-
if (/^(p|div|pre|h1|h2|h3|h4|h5|h6)$/i.test(currentTag)) {
|
|
1859
|
+
if (/^(p|div|pre|h1|h2|h3|h4|h5|h6)$/i.test(el.tagName)) {
|
|
1910
1860
|
const neo = replaceTag(el, tag);
|
|
1911
|
-
if (neo && tag === 'pre')
|
|
1912
|
-
neo.setAttribute('style',
|
|
1913
|
-
}
|
|
1861
|
+
if (neo && tag === 'pre')
|
|
1862
|
+
neo.setAttribute('style', PRE_STYLE);
|
|
1914
1863
|
if (neo)
|
|
1915
1864
|
last = neo;
|
|
1916
1865
|
}
|
|
@@ -1919,10 +1868,10 @@ class StackchRichtextEditor {
|
|
|
1919
1868
|
const sel = window.getSelection();
|
|
1920
1869
|
if (sel) {
|
|
1921
1870
|
sel.removeAllRanges();
|
|
1922
|
-
const
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
sel.addRange(
|
|
1871
|
+
const r = document.createRange();
|
|
1872
|
+
r.selectNodeContents(last);
|
|
1873
|
+
r.collapse(false);
|
|
1874
|
+
sel.addRange(r);
|
|
1926
1875
|
}
|
|
1927
1876
|
}
|
|
1928
1877
|
return;
|
|
@@ -1930,40 +1879,26 @@ class StackchRichtextEditor {
|
|
|
1930
1879
|
}
|
|
1931
1880
|
if (!range.collapsed) {
|
|
1932
1881
|
const el = document.createElement(tag);
|
|
1933
|
-
if (tag === 'pre')
|
|
1934
|
-
el.setAttribute('style',
|
|
1935
|
-
}
|
|
1882
|
+
if (tag === 'pre')
|
|
1883
|
+
el.setAttribute('style', PRE_STYLE);
|
|
1936
1884
|
const frag = range.extractContents();
|
|
1937
1885
|
el.appendChild(frag);
|
|
1938
1886
|
range.insertNode(el);
|
|
1939
1887
|
const sel = window.getSelection();
|
|
1940
1888
|
if (sel) {
|
|
1941
1889
|
sel.removeAllRanges();
|
|
1942
|
-
const
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
sel.addRange(
|
|
1890
|
+
const r = document.createRange();
|
|
1891
|
+
r.selectNodeContents(el);
|
|
1892
|
+
r.collapse(false);
|
|
1893
|
+
sel.addRange(r);
|
|
1946
1894
|
}
|
|
1947
1895
|
}
|
|
1948
1896
|
}
|
|
1949
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type:
|
|
1950
|
-
static
|
|
1951
|
-
{
|
|
1952
|
-
provide: NG_VALUE_ACCESSOR,
|
|
1953
|
-
useExisting: forwardRef(() => StackchRichtextEditor),
|
|
1954
|
-
multi: true,
|
|
1955
|
-
},
|
|
1956
|
-
], viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"stackch_rte\" [class.stackch_rte--disabled]=\"disabled\">\r\n @if (showToolbar) {\r\n <stackch-richtext-editor-toolbar\r\n [cfg]=\"cfg\"\r\n [i18n]=\"i18n\"\r\n [disabled]=\"disabled\"\r\n [fonts]=\"fonts\"\r\n [fontSizes]=\"fontSizes\"\r\n [isBoldActive]=\"isBoldActive\"\r\n [isItalicActive]=\"isItalicActive\"\r\n [isUnderlineActive]=\"isUnderlineActive\"\r\n [canUndo]=\"canUndo\"\r\n [canRedo]=\"canRedo\"\r\n [uiState]=\"{ showFontPanel: showFontPanel, showHeadingMenu: showHeadingMenu, showSpacingMenu: showSpacingMenu, showAlignMenu: showAlignMenu, showColorMenu: showColorMenu, showListMenu: showListMenu }\"\r\n\r\n (undo)=\"undo()\"\r\n (redo)=\"redo()\"\r\n (toggleFontPanel)=\"toggleFontPanel($event)\"\r\n (toggleHeadingMenu)=\"toggleHeadingMenu($event)\"\r\n (toggleSpacingMenu)=\"toggleSpacingMenu($event)\"\r\n (toggleAlignMenu)=\"toggleAlignMenu($event)\"\r\n (toggleColorMenu)=\"toggleColorMenu($event)\"\r\n (toggleListMenu)=\"toggleListMenu($event)\"\r\n (pickFont)=\"onPickFont($any($event))\"\r\n (pickFontSize)=\"onPickFontSize($any($event))\"\r\n (pickAlign)=\"onPickAlign($any($event))\"\r\n (pickList)=\"onPickList($any($event))\"\r\n (pickHeading)=\"onPickHeading($any($event))\"\r\n (pickSpacing)=\"onPickSpacing($any($event).kind, $any($event).target, $any($event).value)\"\r\n (applyColor)=\"applyColor($any($event))\"\r\n (applyHighlight)=\"applyHighlight($any($event))\"\r\n (toggleBold)=\"toggleBold()\"\r\n (toggleItalic)=\"toggleItalic()\"\r\n (toggleUnderline)=\"toggleUnderline()\"\r\n (insertLink)=\"insertLink()\"\r\n (removeFormat)=\"removeFormat()\"\r\n (saveSelectionRequest)=\"saveSelection()\"\r\n />\r\n }\r\n\r\n <div #editor\r\n class=\"stackch_rte__editor\"\r\n [attr.contenteditable]=\"!disabled\"\r\n [attr.data-placeholder]=\"placeholder || i18n.placeholder\"\r\n [style.minHeight.px]=\"minHeight\"\r\n [style.maxHeight.px]=\"maxHeight\"\r\n [style.height.px]=\"height\"\r\n (mouseup)=\"saveSelection()\"\r\n (keyup)=\"onKeyup($event)\"\r\n (input)=\"onInput()\"\r\n (blur)=\"onTouched()\"\r\n (paste)=\"onPaste($event)\"></div>\r\n</div>\r\n", styles: [".stackch_rte{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Arial,sans-serif}.stackch_rte--disabled{opacity:.7;pointer-events:none}.stackch_rte__toolbar{display:flex;flex-wrap:wrap;gap:.25rem;align-items:center;border:1px solid #d0d7de;border-bottom:none;background:#f6f8fa;padding:.25rem;border-radius:6px 6px 0 0}.stackch_rte__btn{appearance:none;border:1px solid #d0d7de;background:#fff;padding:.25rem .5rem;border-radius:4px;cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease;outline:none}.stackch_rte__btn:hover{background:#f3f4f6}.stackch_rte__btn:focus{outline:none;box-shadow:none}.stackch_rte__btn:focus-visible{outline:2px solid rgba(9,105,218,.2)}.stackch_rte__btn.is-active{background:#e7f3ff;border-color:#0969da;color:#084298}.stackch_rte__select{border:1px solid #d0d7de;border-radius:4px;padding:.2rem .4rem;background:#fff}.stackch_rte__color{display:inline-flex;align-items:center;gap:.25rem;border:1px solid #d0d7de;padding:0 .4rem;border-radius:4px;background:#fff}.stackch_rte__color>input{inline-size:1.75rem;block-size:1.5rem;padding:0;border:none;background:none}.stackch_rte__sep{width:1px;height:1.25rem;background:#d0d7de;margin:0 .125rem}.stackch_rte__editor{border:1px solid #d0d7de;border-radius:0 0 6px 6px;padding:.5rem;background:#fff;overflow:auto}.stackch_rte__editor:empty:before{content:attr(data-placeholder);color:#97a1ad;pointer-events:none}.stackch_rte__editor:focus{outline:none;box-shadow:inset 0 0 0 1px #0969da;border-color:#0969da}.stackch_rte__dropdown{position:relative;display:inline-block}.stackch_rte__menu{position:absolute;top:100%;left:0;z-index:2;background:#fff;border:1px solid #d0d7de;border-radius:6px;box-shadow:0 4px 12px #00000014;padding:.25rem;min-width:220px;max-height:220px;overflow:auto}.stackch_rte__menu-item{display:block;width:100%;text-align:left;background:#fff;border:none;padding:.375rem .5rem;border-radius:4px;cursor:pointer}.stackch_rte__menu-item:hover{background:#f3f4f6}.stackch_rte__menu--row{display:flex;flex-direction:row;gap:.25rem;align-items:center;min-width:auto;max-height:none;flex-wrap:nowrap}.stackch_rte__menu--row .stackch_rte__menu-item{display:inline-flex;width:auto;text-align:center;justify-content:center;align-items:center;padding:.3rem .45rem;white-space:nowrap;flex:0 0 auto;word-break:keep-all;overflow-wrap:normal}.stackch_rte__menu--row .stackch_rte__menu-item[style*=\"width:24px\"]{padding:0;width:24px;height:24px}.stackch_rte__menu--grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem 1rem;min-width:420px}.stackch_rte__menu-section{display:flex;flex-direction:column;gap:.25rem}.stackch_rte__menu-title{font-size:12px;color:#57606a;padding:.25rem;text-transform:uppercase;letter-spacing:.04em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: StackchRichtextEditorToolbar, selector: "stackch-richtext-editor-toolbar", inputs: ["cfg", "i18n", "disabled", "fonts", "fontSizes", "isBoldActive", "isItalicActive", "isUnderlineActive", "canUndo", "canRedo", "uiState"], outputs: ["undo", "redo", "toggleFontPanel", "toggleHeadingMenu", "toggleSpacingMenu", "toggleAlignMenu", "toggleColorMenu", "toggleListMenu", "pickFont", "pickFontSize", "pickAlign", "pickList", "pickHeading", "pickSpacing", "applyColor", "applyHighlight", "toggleBold", "toggleItalic", "toggleUnderline", "insertLink", "removeFormat", "saveSelectionRequest"] }] });
|
|
1897
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StackchRichtextEditorBase, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1898
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.4", type: StackchRichtextEditorBase, isStandalone: true, inputs: { placeholder: "placeholder", showToolbar: "showToolbar", fonts: "fonts", fontSizes: "fontSizes", height: "height", minHeight: "minHeight", maxHeight: "maxHeight", disabled: "disabled", config: "config" }, outputs: { valueChange: "valueChange", metricsChange: "metricsChange" }, host: { listeners: { "document:selectionchange": "onSelectionChange()", "document:click": "closeMenus()", "keydown": "onKeydown($event)" } }, viewQueries: [{ propertyName: "editorRef", first: true, predicate: ["editor"], descendants: true, static: true }], ngImport: i0 });
|
|
1957
1899
|
}
|
|
1958
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type:
|
|
1959
|
-
type:
|
|
1960
|
-
args: [{ selector: 'stackch-richtext-editor', standalone: true, imports: [CommonModule, StackchRichtextEditorToolbar], providers: [
|
|
1961
|
-
{
|
|
1962
|
-
provide: NG_VALUE_ACCESSOR,
|
|
1963
|
-
useExisting: forwardRef(() => StackchRichtextEditor),
|
|
1964
|
-
multi: true,
|
|
1965
|
-
},
|
|
1966
|
-
], template: "<div class=\"stackch_rte\" [class.stackch_rte--disabled]=\"disabled\">\r\n @if (showToolbar) {\r\n <stackch-richtext-editor-toolbar\r\n [cfg]=\"cfg\"\r\n [i18n]=\"i18n\"\r\n [disabled]=\"disabled\"\r\n [fonts]=\"fonts\"\r\n [fontSizes]=\"fontSizes\"\r\n [isBoldActive]=\"isBoldActive\"\r\n [isItalicActive]=\"isItalicActive\"\r\n [isUnderlineActive]=\"isUnderlineActive\"\r\n [canUndo]=\"canUndo\"\r\n [canRedo]=\"canRedo\"\r\n [uiState]=\"{ showFontPanel: showFontPanel, showHeadingMenu: showHeadingMenu, showSpacingMenu: showSpacingMenu, showAlignMenu: showAlignMenu, showColorMenu: showColorMenu, showListMenu: showListMenu }\"\r\n\r\n (undo)=\"undo()\"\r\n (redo)=\"redo()\"\r\n (toggleFontPanel)=\"toggleFontPanel($event)\"\r\n (toggleHeadingMenu)=\"toggleHeadingMenu($event)\"\r\n (toggleSpacingMenu)=\"toggleSpacingMenu($event)\"\r\n (toggleAlignMenu)=\"toggleAlignMenu($event)\"\r\n (toggleColorMenu)=\"toggleColorMenu($event)\"\r\n (toggleListMenu)=\"toggleListMenu($event)\"\r\n (pickFont)=\"onPickFont($any($event))\"\r\n (pickFontSize)=\"onPickFontSize($any($event))\"\r\n (pickAlign)=\"onPickAlign($any($event))\"\r\n (pickList)=\"onPickList($any($event))\"\r\n (pickHeading)=\"onPickHeading($any($event))\"\r\n (pickSpacing)=\"onPickSpacing($any($event).kind, $any($event).target, $any($event).value)\"\r\n (applyColor)=\"applyColor($any($event))\"\r\n (applyHighlight)=\"applyHighlight($any($event))\"\r\n (toggleBold)=\"toggleBold()\"\r\n (toggleItalic)=\"toggleItalic()\"\r\n (toggleUnderline)=\"toggleUnderline()\"\r\n (insertLink)=\"insertLink()\"\r\n (removeFormat)=\"removeFormat()\"\r\n (saveSelectionRequest)=\"saveSelection()\"\r\n />\r\n }\r\n\r\n <div #editor\r\n class=\"stackch_rte__editor\"\r\n [attr.contenteditable]=\"!disabled\"\r\n [attr.data-placeholder]=\"placeholder || i18n.placeholder\"\r\n [style.minHeight.px]=\"minHeight\"\r\n [style.maxHeight.px]=\"maxHeight\"\r\n [style.height.px]=\"height\"\r\n (mouseup)=\"saveSelection()\"\r\n (keyup)=\"onKeyup($event)\"\r\n (input)=\"onInput()\"\r\n (blur)=\"onTouched()\"\r\n (paste)=\"onPaste($event)\"></div>\r\n</div>\r\n", styles: [".stackch_rte{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Arial,sans-serif}.stackch_rte--disabled{opacity:.7;pointer-events:none}.stackch_rte__toolbar{display:flex;flex-wrap:wrap;gap:.25rem;align-items:center;border:1px solid #d0d7de;border-bottom:none;background:#f6f8fa;padding:.25rem;border-radius:6px 6px 0 0}.stackch_rte__btn{appearance:none;border:1px solid #d0d7de;background:#fff;padding:.25rem .5rem;border-radius:4px;cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease;outline:none}.stackch_rte__btn:hover{background:#f3f4f6}.stackch_rte__btn:focus{outline:none;box-shadow:none}.stackch_rte__btn:focus-visible{outline:2px solid rgba(9,105,218,.2)}.stackch_rte__btn.is-active{background:#e7f3ff;border-color:#0969da;color:#084298}.stackch_rte__select{border:1px solid #d0d7de;border-radius:4px;padding:.2rem .4rem;background:#fff}.stackch_rte__color{display:inline-flex;align-items:center;gap:.25rem;border:1px solid #d0d7de;padding:0 .4rem;border-radius:4px;background:#fff}.stackch_rte__color>input{inline-size:1.75rem;block-size:1.5rem;padding:0;border:none;background:none}.stackch_rte__sep{width:1px;height:1.25rem;background:#d0d7de;margin:0 .125rem}.stackch_rte__editor{border:1px solid #d0d7de;border-radius:0 0 6px 6px;padding:.5rem;background:#fff;overflow:auto}.stackch_rte__editor:empty:before{content:attr(data-placeholder);color:#97a1ad;pointer-events:none}.stackch_rte__editor:focus{outline:none;box-shadow:inset 0 0 0 1px #0969da;border-color:#0969da}.stackch_rte__dropdown{position:relative;display:inline-block}.stackch_rte__menu{position:absolute;top:100%;left:0;z-index:2;background:#fff;border:1px solid #d0d7de;border-radius:6px;box-shadow:0 4px 12px #00000014;padding:.25rem;min-width:220px;max-height:220px;overflow:auto}.stackch_rte__menu-item{display:block;width:100%;text-align:left;background:#fff;border:none;padding:.375rem .5rem;border-radius:4px;cursor:pointer}.stackch_rte__menu-item:hover{background:#f3f4f6}.stackch_rte__menu--row{display:flex;flex-direction:row;gap:.25rem;align-items:center;min-width:auto;max-height:none;flex-wrap:nowrap}.stackch_rte__menu--row .stackch_rte__menu-item{display:inline-flex;width:auto;text-align:center;justify-content:center;align-items:center;padding:.3rem .45rem;white-space:nowrap;flex:0 0 auto;word-break:keep-all;overflow-wrap:normal}.stackch_rte__menu--row .stackch_rte__menu-item[style*=\"width:24px\"]{padding:0;width:24px;height:24px}.stackch_rte__menu--grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem 1rem;min-width:420px}.stackch_rte__menu-section{display:flex;flex-direction:column;gap:.25rem}.stackch_rte__menu-title{font-size:12px;color:#57606a;padding:.25rem;text-transform:uppercase;letter-spacing:.04em}\n"] }]
|
|
1900
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StackchRichtextEditorBase, decorators: [{
|
|
1901
|
+
type: Directive
|
|
1967
1902
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { placeholder: [{
|
|
1968
1903
|
type: Input
|
|
1969
1904
|
}], showToolbar: [{
|
|
@@ -2000,6 +1935,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2000
1935
|
args: ['keydown', ['$event']]
|
|
2001
1936
|
}] } });
|
|
2002
1937
|
|
|
1938
|
+
class StackchRichtextEditor extends StackchRichtextEditorBase {
|
|
1939
|
+
logPrefix = '[RTE]';
|
|
1940
|
+
constructor(cdr) {
|
|
1941
|
+
super(cdr);
|
|
1942
|
+
}
|
|
1943
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StackchRichtextEditor, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1944
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: StackchRichtextEditor, isStandalone: true, selector: "stackch-richtext-editor", providers: [
|
|
1945
|
+
{
|
|
1946
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1947
|
+
useExisting: forwardRef(() => StackchRichtextEditor),
|
|
1948
|
+
multi: true,
|
|
1949
|
+
},
|
|
1950
|
+
], usesInheritance: true, ngImport: i0, template: "<div class=\"stackch_rte\" [class.stackch_rte--disabled]=\"disabled\">\r\n @if (showToolbar) {\r\n <stackch-richtext-editor-toolbar\r\n [cfg]=\"cfg\"\r\n [i18n]=\"i18n\"\r\n [disabled]=\"disabled\"\r\n [fonts]=\"fonts\"\r\n [fontSizes]=\"fontSizes\"\r\n [isBoldActive]=\"isBoldActive\"\r\n [isItalicActive]=\"isItalicActive\"\r\n [isUnderlineActive]=\"isUnderlineActive\"\r\n [canUndo]=\"canUndo\"\r\n [canRedo]=\"canRedo\"\r\n [uiState]=\"{ showFontPanel: showFontPanel, showHeadingMenu: showHeadingMenu, showSpacingMenu: showSpacingMenu, showAlignMenu: showAlignMenu, showColorMenu: showColorMenu, showListMenu: showListMenu }\"\r\n\r\n (undo)=\"undo()\"\r\n (redo)=\"redo()\"\r\n (toggleFontPanel)=\"toggleFontPanel($event)\"\r\n (toggleHeadingMenu)=\"toggleHeadingMenu($event)\"\r\n (toggleSpacingMenu)=\"toggleSpacingMenu($event)\"\r\n (toggleAlignMenu)=\"toggleAlignMenu($event)\"\r\n (toggleColorMenu)=\"toggleColorMenu($event)\"\r\n (toggleListMenu)=\"toggleListMenu($event)\"\r\n (pickFont)=\"onPickFont($any($event))\"\r\n (pickFontSize)=\"onPickFontSize($any($event))\"\r\n (pickAlign)=\"onPickAlign($any($event))\"\r\n (pickList)=\"onPickList($any($event))\"\r\n (pickHeading)=\"onPickHeading($any($event))\"\r\n (pickSpacing)=\"onPickSpacing($any($event).kind, $any($event).target, $any($event).value)\"\r\n (applyColor)=\"applyColor($any($event))\"\r\n (applyHighlight)=\"applyHighlight($any($event))\"\r\n (toggleBold)=\"toggleBold()\"\r\n (toggleItalic)=\"toggleItalic()\"\r\n (toggleUnderline)=\"toggleUnderline()\"\r\n (insertLink)=\"insertLink()\"\r\n (removeFormat)=\"removeFormat()\"\r\n (saveSelectionRequest)=\"saveSelection()\"\r\n />\r\n }\r\n\r\n <div #editor\r\n class=\"stackch_rte__editor\"\r\n [attr.contenteditable]=\"!disabled\"\r\n [attr.data-placeholder]=\"placeholder || i18n.placeholder\"\r\n [style.minHeight.px]=\"minHeight\"\r\n [style.maxHeight.px]=\"maxHeight\"\r\n [style.height.px]=\"height\"\r\n (mouseup)=\"saveSelection()\"\r\n (keyup)=\"onKeyup($event)\"\r\n (input)=\"onInput()\"\r\n (blur)=\"onTouched()\"\r\n (paste)=\"onPaste($event)\"></div>\r\n</div>\r\n", styles: [".stackch_rte{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Arial,sans-serif}.stackch_rte--disabled{opacity:.7;pointer-events:none}.stackch_rte__toolbar{display:flex;flex-wrap:wrap;gap:.25rem;align-items:center;border:1px solid #d0d7de;border-bottom:none;background:#f6f8fa;padding:.25rem;border-radius:6px 6px 0 0}.stackch_rte__btn{appearance:none;border:1px solid #d0d7de;background:#fff;padding:.25rem .5rem;border-radius:4px;cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease;outline:none}.stackch_rte__btn:hover{background:#f3f4f6}.stackch_rte__btn:focus{outline:none;box-shadow:none}.stackch_rte__btn:focus-visible{outline:2px solid rgba(9,105,218,.2)}.stackch_rte__btn.is-active{background:#e7f3ff;border-color:#0969da;color:#084298}.stackch_rte__select{border:1px solid #d0d7de;border-radius:4px;padding:.2rem .4rem;background:#fff}.stackch_rte__color{display:inline-flex;align-items:center;gap:.25rem;border:1px solid #d0d7de;padding:0 .4rem;border-radius:4px;background:#fff}.stackch_rte__color>input{inline-size:1.75rem;block-size:1.5rem;padding:0;border:none;background:none}.stackch_rte__sep{width:1px;height:1.25rem;background:#d0d7de;margin:0 .125rem}.stackch_rte__editor{border:1px solid #d0d7de;border-radius:0 0 6px 6px;padding:.5rem;background:#fff;overflow:auto}.stackch_rte__editor:empty:before{content:attr(data-placeholder);color:#97a1ad;pointer-events:none}.stackch_rte__editor:focus{outline:none;box-shadow:inset 0 0 0 1px #0969da;border-color:#0969da}.stackch_rte__dropdown{position:relative;display:inline-block}.stackch_rte__menu{position:absolute;top:100%;left:0;z-index:2;background:#fff;border:1px solid #d0d7de;border-radius:6px;box-shadow:0 4px 12px #00000014;padding:.25rem;min-width:220px;max-height:220px;overflow:auto}.stackch_rte__menu-item{display:block;width:100%;text-align:left;background:#fff;border:none;padding:.375rem .5rem;border-radius:4px;cursor:pointer}.stackch_rte__menu-item:hover{background:#f3f4f6}.stackch_rte__menu--row{display:flex;flex-direction:row;gap:.25rem;align-items:center;min-width:auto;max-height:none;flex-wrap:nowrap}.stackch_rte__menu--row .stackch_rte__menu-item{display:inline-flex;width:auto;text-align:center;justify-content:center;align-items:center;padding:.3rem .45rem;white-space:nowrap;flex:0 0 auto;word-break:keep-all;overflow-wrap:normal}.stackch_rte__menu--row .stackch_rte__menu-item[style*=\"width:24px\"]{padding:0;width:24px;height:24px}.stackch_rte__menu--grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem 1rem;min-width:420px}.stackch_rte__menu-section{display:flex;flex-direction:column;gap:.25rem}.stackch_rte__menu-title{font-size:12px;color:#57606a;padding:.25rem;text-transform:uppercase;letter-spacing:.04em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: StackchRichtextEditorToolbar, selector: "stackch-richtext-editor-toolbar", inputs: ["cfg", "i18n", "disabled", "fonts", "fontSizes", "isBoldActive", "isItalicActive", "isUnderlineActive", "canUndo", "canRedo", "uiState"], outputs: ["undo", "redo", "toggleFontPanel", "toggleHeadingMenu", "toggleSpacingMenu", "toggleAlignMenu", "toggleColorMenu", "toggleListMenu", "pickFont", "pickFontSize", "pickAlign", "pickList", "pickHeading", "pickSpacing", "applyColor", "applyHighlight", "toggleBold", "toggleItalic", "toggleUnderline", "insertLink", "removeFormat", "saveSelectionRequest"] }] });
|
|
1951
|
+
}
|
|
1952
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: StackchRichtextEditor, decorators: [{
|
|
1953
|
+
type: Component,
|
|
1954
|
+
args: [{ selector: 'stackch-richtext-editor', standalone: true, imports: [CommonModule, StackchRichtextEditorToolbar], providers: [
|
|
1955
|
+
{
|
|
1956
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1957
|
+
useExisting: forwardRef(() => StackchRichtextEditor),
|
|
1958
|
+
multi: true,
|
|
1959
|
+
},
|
|
1960
|
+
], template: "<div class=\"stackch_rte\" [class.stackch_rte--disabled]=\"disabled\">\r\n @if (showToolbar) {\r\n <stackch-richtext-editor-toolbar\r\n [cfg]=\"cfg\"\r\n [i18n]=\"i18n\"\r\n [disabled]=\"disabled\"\r\n [fonts]=\"fonts\"\r\n [fontSizes]=\"fontSizes\"\r\n [isBoldActive]=\"isBoldActive\"\r\n [isItalicActive]=\"isItalicActive\"\r\n [isUnderlineActive]=\"isUnderlineActive\"\r\n [canUndo]=\"canUndo\"\r\n [canRedo]=\"canRedo\"\r\n [uiState]=\"{ showFontPanel: showFontPanel, showHeadingMenu: showHeadingMenu, showSpacingMenu: showSpacingMenu, showAlignMenu: showAlignMenu, showColorMenu: showColorMenu, showListMenu: showListMenu }\"\r\n\r\n (undo)=\"undo()\"\r\n (redo)=\"redo()\"\r\n (toggleFontPanel)=\"toggleFontPanel($event)\"\r\n (toggleHeadingMenu)=\"toggleHeadingMenu($event)\"\r\n (toggleSpacingMenu)=\"toggleSpacingMenu($event)\"\r\n (toggleAlignMenu)=\"toggleAlignMenu($event)\"\r\n (toggleColorMenu)=\"toggleColorMenu($event)\"\r\n (toggleListMenu)=\"toggleListMenu($event)\"\r\n (pickFont)=\"onPickFont($any($event))\"\r\n (pickFontSize)=\"onPickFontSize($any($event))\"\r\n (pickAlign)=\"onPickAlign($any($event))\"\r\n (pickList)=\"onPickList($any($event))\"\r\n (pickHeading)=\"onPickHeading($any($event))\"\r\n (pickSpacing)=\"onPickSpacing($any($event).kind, $any($event).target, $any($event).value)\"\r\n (applyColor)=\"applyColor($any($event))\"\r\n (applyHighlight)=\"applyHighlight($any($event))\"\r\n (toggleBold)=\"toggleBold()\"\r\n (toggleItalic)=\"toggleItalic()\"\r\n (toggleUnderline)=\"toggleUnderline()\"\r\n (insertLink)=\"insertLink()\"\r\n (removeFormat)=\"removeFormat()\"\r\n (saveSelectionRequest)=\"saveSelection()\"\r\n />\r\n }\r\n\r\n <div #editor\r\n class=\"stackch_rte__editor\"\r\n [attr.contenteditable]=\"!disabled\"\r\n [attr.data-placeholder]=\"placeholder || i18n.placeholder\"\r\n [style.minHeight.px]=\"minHeight\"\r\n [style.maxHeight.px]=\"maxHeight\"\r\n [style.height.px]=\"height\"\r\n (mouseup)=\"saveSelection()\"\r\n (keyup)=\"onKeyup($event)\"\r\n (input)=\"onInput()\"\r\n (blur)=\"onTouched()\"\r\n (paste)=\"onPaste($event)\"></div>\r\n</div>\r\n", styles: [".stackch_rte{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Arial,sans-serif}.stackch_rte--disabled{opacity:.7;pointer-events:none}.stackch_rte__toolbar{display:flex;flex-wrap:wrap;gap:.25rem;align-items:center;border:1px solid #d0d7de;border-bottom:none;background:#f6f8fa;padding:.25rem;border-radius:6px 6px 0 0}.stackch_rte__btn{appearance:none;border:1px solid #d0d7de;background:#fff;padding:.25rem .5rem;border-radius:4px;cursor:pointer;transition:background .12s ease,border-color .12s ease,color .12s ease;outline:none}.stackch_rte__btn:hover{background:#f3f4f6}.stackch_rte__btn:focus{outline:none;box-shadow:none}.stackch_rte__btn:focus-visible{outline:2px solid rgba(9,105,218,.2)}.stackch_rte__btn.is-active{background:#e7f3ff;border-color:#0969da;color:#084298}.stackch_rte__select{border:1px solid #d0d7de;border-radius:4px;padding:.2rem .4rem;background:#fff}.stackch_rte__color{display:inline-flex;align-items:center;gap:.25rem;border:1px solid #d0d7de;padding:0 .4rem;border-radius:4px;background:#fff}.stackch_rte__color>input{inline-size:1.75rem;block-size:1.5rem;padding:0;border:none;background:none}.stackch_rte__sep{width:1px;height:1.25rem;background:#d0d7de;margin:0 .125rem}.stackch_rte__editor{border:1px solid #d0d7de;border-radius:0 0 6px 6px;padding:.5rem;background:#fff;overflow:auto}.stackch_rte__editor:empty:before{content:attr(data-placeholder);color:#97a1ad;pointer-events:none}.stackch_rte__editor:focus{outline:none;box-shadow:inset 0 0 0 1px #0969da;border-color:#0969da}.stackch_rte__dropdown{position:relative;display:inline-block}.stackch_rte__menu{position:absolute;top:100%;left:0;z-index:2;background:#fff;border:1px solid #d0d7de;border-radius:6px;box-shadow:0 4px 12px #00000014;padding:.25rem;min-width:220px;max-height:220px;overflow:auto}.stackch_rte__menu-item{display:block;width:100%;text-align:left;background:#fff;border:none;padding:.375rem .5rem;border-radius:4px;cursor:pointer}.stackch_rte__menu-item:hover{background:#f3f4f6}.stackch_rte__menu--row{display:flex;flex-direction:row;gap:.25rem;align-items:center;min-width:auto;max-height:none;flex-wrap:nowrap}.stackch_rte__menu--row .stackch_rte__menu-item{display:inline-flex;width:auto;text-align:center;justify-content:center;align-items:center;padding:.3rem .45rem;white-space:nowrap;flex:0 0 auto;word-break:keep-all;overflow-wrap:normal}.stackch_rte__menu--row .stackch_rte__menu-item[style*=\"width:24px\"]{padding:0;width:24px;height:24px}.stackch_rte__menu--grid{display:grid;grid-template-columns:1fr 1fr;gap:.5rem 1rem;min-width:420px}.stackch_rte__menu-section{display:flex;flex-direction:column;gap:.25rem}.stackch_rte__menu-title{font-size:12px;color:#57606a;padding:.25rem;text-transform:uppercase;letter-spacing:.04em}\n"] }]
|
|
1961
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
|
|
1962
|
+
|
|
2003
1963
|
/*
|
|
2004
1964
|
* Public API Surface of richtext-editor
|
|
2005
1965
|
*/
|
|
@@ -2008,5 +1968,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImpor
|
|
|
2008
1968
|
* Generated bundle index. Do not edit.
|
|
2009
1969
|
*/
|
|
2010
1970
|
|
|
2011
|
-
export { STACKCH_RTE_I18N_DE, STACKCH_RTE_I18N_FR, STACKCH_RTE_I18N_IT, StackchRichtextEditor, StackchRichtextEditorConfig, StackchRichtextEditorI18n, StackchRichtextEditorToolbar };
|
|
1971
|
+
export { STACKCH_RTE_I18N_DE, STACKCH_RTE_I18N_FR, STACKCH_RTE_I18N_IT, StackchRichtextEditor, StackchRichtextEditorBase, StackchRichtextEditorConfig, StackchRichtextEditorI18n, StackchRichtextEditorToolbar };
|
|
2012
1972
|
//# sourceMappingURL=stackch-angular-richtext-editor.mjs.map
|