kempo-ui 0.3.8 → 0.3.10
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.
- package/dist/components/CodeEditor.js +96 -0
- package/dist/components/HtmlEditor.js +155 -30
- package/dist/components/codeEditorControls/CodeEditorControl.js +17 -0
- package/dist/components/codeEditorControls/ControlGroup.js +12 -0
- package/dist/components/codeEditorControls/ControlSpacer.js +6 -0
- package/dist/components/codeEditorControls/CopyCode.js +9 -0
- package/dist/components/codeEditorControls/EditorTheme.js +26 -0
- package/dist/components/codeEditorControls/FindReplace.js +7 -0
- package/dist/components/codeEditorControls/FoldAll.js +7 -0
- package/dist/components/codeEditorControls/FontSize.js +13 -0
- package/dist/components/codeEditorControls/FormatCode.js +9 -0
- package/dist/components/codeEditorControls/Fullscreen.js +12 -0
- package/dist/components/codeEditorControls/LanguageSelect.js +15 -0
- package/dist/components/codeEditorControls/Minimap.js +8 -0
- package/dist/components/codeEditorControls/Redo.js +7 -0
- package/dist/components/codeEditorControls/Undo.js +7 -0
- package/dist/components/codeEditorControls/WordWrap.js +8 -0
- package/dist/components/htmlEditorControls/AlignCenter.js +4 -4
- package/dist/components/htmlEditorControls/AlignJustify.js +4 -4
- package/dist/components/htmlEditorControls/AlignLeft.js +4 -4
- package/dist/components/htmlEditorControls/AlignRight.js +4 -4
- package/dist/components/htmlEditorControls/Bold.js +4 -4
- package/dist/components/htmlEditorControls/BulletList.js +4 -4
- package/dist/components/htmlEditorControls/ClearFormatting.js +4 -4
- package/dist/components/htmlEditorControls/CodeBlock.js +2 -2
- package/dist/components/htmlEditorControls/ControlGroup.js +2 -4
- package/dist/components/htmlEditorControls/CreateLink.js +3 -3
- package/dist/components/htmlEditorControls/FormatBlock.js +4 -4
- package/dist/components/htmlEditorControls/FormatCode.js +1 -0
- package/dist/components/htmlEditorControls/HtmlEditorControl.js +2 -2
- package/dist/components/htmlEditorControls/InlineCode.js +2 -2
- package/dist/components/htmlEditorControls/InsertTable.js +3 -3
- package/dist/components/htmlEditorControls/Italic.js +4 -4
- package/dist/components/htmlEditorControls/Mode.js +3 -3
- package/dist/components/htmlEditorControls/NumberList.js +4 -4
- package/dist/components/htmlEditorControls/Strikethrough.js +4 -4
- package/dist/components/htmlEditorControls/TextBackgroundColor.js +1 -1
- package/dist/components/htmlEditorControls/TextColor.js +1 -1
- package/dist/components/htmlEditorControls/Underline.js +4 -4
- package/docs/components/accordion.html +2 -0
- package/docs/components/aside.html +2 -0
- package/docs/components/card.html +2 -0
- package/docs/components/code-editor.html +491 -0
- package/docs/components/color-picker.html +2 -0
- package/docs/components/content-slider.html +2 -0
- package/docs/components/context.html +2 -0
- package/docs/components/dialog.html +2 -0
- package/docs/components/dropdown.html +2 -0
- package/docs/components/filter-list.html +2 -0
- package/docs/components/focus-capture.html +2 -0
- package/docs/components/html-editor.html +525 -212
- package/docs/components/hybrid-component.html +2 -0
- package/docs/components/icon.html +2 -0
- package/docs/components/import.html +2 -0
- package/docs/components/light-component.html +2 -0
- package/docs/components/nav-spacer.html +2 -0
- package/docs/components/nav.html +2 -0
- package/docs/components/photo-viewer.html +2 -0
- package/docs/components/resize.html +2 -0
- package/docs/components/shadow-component.html +2 -0
- package/docs/components/show-more.html +2 -0
- package/docs/components/sortable.html +2 -0
- package/docs/components/spinner.html +2 -0
- package/docs/components/split.html +2 -0
- package/docs/components/table.html +2 -0
- package/docs/components/tableControls.html +2 -0
- package/docs/components/tableCustomFields.html +2 -0
- package/docs/components/tableFetchRecords.html +2 -0
- package/docs/components/tableFieldSortHide.html +2 -0
- package/docs/components/tablePagination.html +2 -0
- package/docs/components/tablePlaceholder.html +2 -0
- package/docs/components/tableRecordEditing.html +2 -0
- package/docs/components/tableRecordFiltering.html +2 -0
- package/docs/components/tableRecordHiding.html +2 -0
- package/docs/components/tableRecordSearching.html +2 -0
- package/docs/components/tableRecordSelection.html +2 -0
- package/docs/components/tableRowControls.html +2 -0
- package/docs/components/tableServerSync.html +2 -0
- package/docs/components/tableSorting.html +2 -0
- package/docs/components/tabs.html +2 -0
- package/docs/components/tags.html +2 -0
- package/docs/components/theme-select.html +2 -0
- package/docs/components/theme-switcher.html +2 -0
- package/docs/components/timestamp.html +2 -0
- package/docs/components/toast.html +2 -0
- package/docs/components/toggle.html +2 -0
- package/docs/components/tree.html +2 -0
- package/docs/icons/auto_fix_high.svg +1 -0
- package/docs/icons/content_copy.svg +1 -0
- package/docs/icons/contrast.svg +1 -0
- package/docs/icons/frame_source.svg +1 -0
- package/docs/icons/fullscreen.svg +1 -0
- package/docs/icons/fullscreen_exit.svg +1 -0
- package/docs/icons/map.svg +1 -0
- package/docs/icons/redo.svg +1 -0
- package/docs/icons/text_decrease.svg +1 -0
- package/docs/icons/text_increase.svg +1 -0
- package/docs/icons/undo.svg +1 -0
- package/docs/icons/unfold_less.svg +1 -0
- package/docs/icons/unfold_more.svg +1 -0
- package/docs/icons/wrap_text.svg +1 -0
- package/docs/index.html +8 -0
- package/docs/src/components/CodeEditor.js +96 -0
- package/docs/src/components/HtmlEditor.js +155 -30
- package/docs/src/components/codeEditorControls/CodeEditorControl.js +17 -0
- package/docs/src/components/codeEditorControls/ControlGroup.js +12 -0
- package/docs/src/components/codeEditorControls/ControlSpacer.js +6 -0
- package/docs/src/components/codeEditorControls/CopyCode.js +9 -0
- package/docs/src/components/codeEditorControls/EditorTheme.js +26 -0
- package/docs/src/components/codeEditorControls/FindReplace.js +7 -0
- package/docs/src/components/codeEditorControls/FoldAll.js +7 -0
- package/docs/src/components/codeEditorControls/FontSize.js +13 -0
- package/docs/src/components/codeEditorControls/FormatCode.js +9 -0
- package/docs/src/components/codeEditorControls/Fullscreen.js +12 -0
- package/docs/src/components/codeEditorControls/LanguageSelect.js +15 -0
- package/docs/src/components/codeEditorControls/Minimap.js +8 -0
- package/docs/src/components/codeEditorControls/Redo.js +7 -0
- package/docs/src/components/codeEditorControls/Undo.js +7 -0
- package/docs/src/components/codeEditorControls/WordWrap.js +8 -0
- package/docs/src/components/htmlEditorControls/AlignCenter.js +4 -4
- package/docs/src/components/htmlEditorControls/AlignJustify.js +4 -4
- package/docs/src/components/htmlEditorControls/AlignLeft.js +4 -4
- package/docs/src/components/htmlEditorControls/AlignRight.js +4 -4
- package/docs/src/components/htmlEditorControls/Bold.js +4 -4
- package/docs/src/components/htmlEditorControls/BulletList.js +4 -4
- package/docs/src/components/htmlEditorControls/ClearFormatting.js +4 -4
- package/docs/src/components/htmlEditorControls/CodeBlock.js +2 -2
- package/docs/src/components/htmlEditorControls/ControlGroup.js +2 -4
- package/docs/src/components/htmlEditorControls/CreateLink.js +3 -3
- package/docs/src/components/htmlEditorControls/FormatBlock.js +4 -4
- package/docs/src/components/htmlEditorControls/FormatCode.js +1 -0
- package/docs/src/components/htmlEditorControls/HtmlEditorControl.js +2 -2
- package/docs/src/components/htmlEditorControls/InlineCode.js +2 -2
- package/docs/src/components/htmlEditorControls/InsertTable.js +3 -3
- package/docs/src/components/htmlEditorControls/Italic.js +4 -4
- package/docs/src/components/htmlEditorControls/Mode.js +3 -3
- package/docs/src/components/htmlEditorControls/NumberList.js +4 -4
- package/docs/src/components/htmlEditorControls/Strikethrough.js +4 -4
- package/docs/src/components/htmlEditorControls/TextBackgroundColor.js +1 -1
- package/docs/src/components/htmlEditorControls/TextColor.js +1 -1
- package/docs/src/components/htmlEditorControls/Underline.js +4 -4
- package/docs/utils/context.html +2 -0
- package/docs/utils/cookie.html +2 -0
- package/docs/utils/debounce.html +2 -0
- package/docs/utils/drag.html +2 -0
- package/docs/utils/elevation.html +2 -0
- package/docs/utils/formatTimestamp.html +2 -0
- package/docs/utils/object.html +2 -0
- package/docs/utils/propConverters.html +2 -0
- package/docs/utils/string.html +2 -0
- package/docs/utils/theme.html +2 -0
- package/docs/utils/toTitleCase.html +2 -0
- package/docs/utils/type.html +2 -0
- package/docs/utils/wait.html +2 -0
- package/docs-src/components/code-editor.page.html +235 -0
- package/docs-src/components/html-editor.page.html +528 -214
- package/docs-src/index.page.html +6 -0
- package/docs-src/nav.fragment.html +2 -0
- package/icons/auto_fix_high.svg +1 -0
- package/icons/content_copy.svg +1 -0
- package/icons/contrast.svg +1 -0
- package/icons/frame_source.svg +1 -0
- package/icons/fullscreen.svg +1 -0
- package/icons/fullscreen_exit.svg +1 -0
- package/icons/map.svg +1 -0
- package/icons/redo.svg +1 -0
- package/icons/text_decrease.svg +1 -0
- package/icons/text_increase.svg +1 -0
- package/icons/undo.svg +1 -0
- package/icons/unfold_less.svg +1 -0
- package/icons/unfold_more.svg +1 -0
- package/icons/wrap_text.svg +1 -0
- package/llm.txt +2 -1
- package/package.json +3 -3
- package/src/components/CodeEditor.js +495 -0
- package/src/components/HtmlEditor.js +527 -152
- package/src/components/codeEditorControls/CodeEditorControl.js +134 -0
- package/src/components/codeEditorControls/ControlGroup.js +70 -0
- package/src/components/codeEditorControls/ControlSpacer.js +23 -0
- package/src/components/codeEditorControls/CopyCode.js +37 -0
- package/src/components/codeEditorControls/EditorTheme.js +81 -0
- package/src/components/codeEditorControls/FindReplace.js +35 -0
- package/src/components/codeEditorControls/FoldAll.js +49 -0
- package/src/components/codeEditorControls/FontSize.js +45 -0
- package/src/components/codeEditorControls/FormatCode.js +37 -0
- package/src/components/codeEditorControls/Fullscreen.js +72 -0
- package/src/components/codeEditorControls/LanguageSelect.js +74 -0
- package/src/components/codeEditorControls/Minimap.js +60 -0
- package/src/components/codeEditorControls/Redo.js +35 -0
- package/src/components/codeEditorControls/Undo.js +35 -0
- package/src/components/codeEditorControls/WordWrap.js +60 -0
- package/src/components/htmlEditorControls/AlignCenter.js +2 -4
- package/src/components/htmlEditorControls/AlignJustify.js +2 -4
- package/src/components/htmlEditorControls/AlignLeft.js +2 -4
- package/src/components/htmlEditorControls/AlignRight.js +2 -4
- package/src/components/htmlEditorControls/Bold.js +2 -4
- package/src/components/htmlEditorControls/BulletList.js +2 -4
- package/src/components/htmlEditorControls/ClearFormatting.js +2 -4
- package/src/components/htmlEditorControls/CodeBlock.js +3 -19
- package/src/components/htmlEditorControls/ControlGroup.js +16 -41
- package/src/components/htmlEditorControls/CreateLink.js +3 -5
- package/src/components/htmlEditorControls/FormatBlock.js +2 -4
- package/src/components/htmlEditorControls/FormatCode.js +7 -0
- package/src/components/htmlEditorControls/HtmlEditorControl.js +43 -5
- package/src/components/htmlEditorControls/InlineCode.js +3 -5
- package/src/components/htmlEditorControls/InsertTable.js +9 -53
- package/src/components/htmlEditorControls/Italic.js +2 -4
- package/src/components/htmlEditorControls/Mode.js +2 -0
- package/src/components/htmlEditorControls/NumberList.js +2 -4
- package/src/components/htmlEditorControls/Strikethrough.js +2 -4
- package/src/components/htmlEditorControls/TextBackgroundColor.js +0 -6
- package/src/components/htmlEditorControls/TextColor.js +0 -6
- package/src/components/htmlEditorControls/Underline.js +2 -4
- package/tests/components/CodeEditor.browser-test.js +297 -0
- package/tests/components/HtmlEditor.browser-test.js +207 -0
- package/tests/components/codeEditorControls/CopyCode.browser-test.js +57 -0
- package/tests/components/codeEditorControls/EditorTheme.browser-test.js +70 -0
- package/tests/components/codeEditorControls/FindReplace.browser-test.js +57 -0
- package/tests/components/codeEditorControls/FoldAll.browser-test.js +92 -0
- package/tests/components/codeEditorControls/FontSize.browser-test.js +74 -0
- package/tests/components/codeEditorControls/Fullscreen.browser-test.js +152 -0
- package/tests/components/codeEditorControls/LanguageSelect.browser-test.js +82 -0
- package/tests/components/codeEditorControls/Minimap.browser-test.js +84 -0
- package/tests/components/codeEditorControls/ModeVisibility.browser-test.js +82 -0
- package/tests/components/codeEditorControls/UndoRedo.browser-test.js +85 -0
- package/tests/components/codeEditorControls/WordWrap.browser-test.js +95 -0
- package/tests/components/htmlEditorControls/Align.browser-test.js +203 -0
- package/tests/components/htmlEditorControls/Bold.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/BulletList.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/CharacterCount.browser-test.js +106 -0
- package/tests/components/htmlEditorControls/ClearFormatting.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/CodeBlock.browser-test.js +143 -0
- package/tests/components/htmlEditorControls/ControlGroup.browser-test.js +116 -0
- package/tests/components/htmlEditorControls/ControlSpacer.browser-test.js +69 -0
- package/tests/components/htmlEditorControls/CreateLink.browser-test.js +129 -0
- package/tests/components/htmlEditorControls/DropdownControl.browser-test.js +138 -0
- package/tests/components/htmlEditorControls/FormatBlock.browser-test.js +163 -0
- package/tests/components/htmlEditorControls/FormatCode.browser-test.js +155 -0
- package/tests/components/htmlEditorControls/InlineCode.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/InsertTable.browser-test.js +129 -0
- package/tests/components/htmlEditorControls/Italic.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/Mode.browser-test.js +138 -0
- package/tests/components/htmlEditorControls/NumberList.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/Strikethrough.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/TextBackgroundColor.browser-test.js +136 -0
- package/tests/components/htmlEditorControls/TextColor.browser-test.js +136 -0
- package/tests/components/htmlEditorControls/Underline.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/WordCount.browser-test.js +106 -0
|
@@ -6,7 +6,7 @@ import { getCalculatedTheme, subscribeToTheme } from '../utils/theme.js';
|
|
|
6
6
|
import Dialog from './Dialog.js';
|
|
7
7
|
|
|
8
8
|
/*
|
|
9
|
-
|
|
9
|
+
Default CDN URLs
|
|
10
10
|
*/
|
|
11
11
|
const LEXICAL_VERSION = '0.43.0';
|
|
12
12
|
const MONACO_VERSION = '0.52.2';
|
|
@@ -23,11 +23,13 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
23
23
|
value: { type: String, reflect: true },
|
|
24
24
|
selection: { type: Object, state: true },
|
|
25
25
|
mode: { type: String, reflect: true },
|
|
26
|
+
controls: { type: String, reflect: true },
|
|
26
27
|
lexicalSrc: { type: String, attribute: 'lexical-src' },
|
|
27
28
|
monacoSrc: { type: String, attribute: 'monaco-src' },
|
|
28
29
|
nodes: { type: String },
|
|
29
30
|
hasTopToolbar: { type: Boolean, state: true },
|
|
30
|
-
hasBottomToolbar: { type: Boolean, state: true }
|
|
31
|
+
hasBottomToolbar: { type: Boolean, state: true },
|
|
32
|
+
fullscreen: { type: Boolean, reflect: true }
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
constructor() {
|
|
@@ -38,6 +40,8 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
38
40
|
this.selection = null;
|
|
39
41
|
this.cursor = null;
|
|
40
42
|
this.mode = 'visual';
|
|
43
|
+
this.controls = '';
|
|
44
|
+
this.controlsLoaded = false;
|
|
41
45
|
this.lexicalSrc = '';
|
|
42
46
|
this.monacoSrc = '';
|
|
43
47
|
this.nodes = '';
|
|
@@ -48,6 +52,11 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
48
52
|
this.savedSelection = null;
|
|
49
53
|
this.lexicalEditor = null;
|
|
50
54
|
this.monacoEditor = null;
|
|
55
|
+
this.editorTheme = 'auto';
|
|
56
|
+
this.wordWrap = true;
|
|
57
|
+
this.minimapEnabled = false;
|
|
58
|
+
this.fontSize = 14;
|
|
59
|
+
this.fullscreen = false;
|
|
51
60
|
this.lx = {};
|
|
52
61
|
this.debouncedSyncValue = debounce(() => this.syncValueFromLexical(), 300);
|
|
53
62
|
}
|
|
@@ -57,7 +66,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
57
66
|
*/
|
|
58
67
|
connectedCallback() {
|
|
59
68
|
super.connectedCallback();
|
|
60
|
-
if(this.hasAttribute('value')){
|
|
69
|
+
if (this.hasAttribute('value')) {
|
|
61
70
|
this.value = this.getAttribute('value');
|
|
62
71
|
}
|
|
63
72
|
this.slotObserver = new MutationObserver(() => this.updateToolbarVisibility());
|
|
@@ -71,21 +80,32 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
71
80
|
this.cleanupFns?.forEach(fn => fn?.());
|
|
72
81
|
this.monacoEditor?.dispose();
|
|
73
82
|
this.unsubscribeTheme?.();
|
|
74
|
-
if(this.syncShadowSelection) document.removeEventListener('selectionchange', this.syncShadowSelection);
|
|
83
|
+
if (this.syncShadowSelection) document.removeEventListener('selectionchange', this.syncShadowSelection);
|
|
84
|
+
if(this.fullscreen) this.exitFullscreen();
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
updateToolbarVisibility() {
|
|
78
|
-
|
|
79
|
-
|
|
88
|
+
const slots = new Set(Array.from(this.children).map(c => c.getAttribute('slot')));
|
|
89
|
+
const set = this.constructor.controlSets[this.controls] ?? null;
|
|
90
|
+
this.hasTopToolbar =
|
|
91
|
+
!!(set?.topLeft || set?.topRight) ||
|
|
92
|
+
['toolbar-top', 'toolbar-top-left', 'toolbar-top-right'].some(s => slots.has(s));
|
|
93
|
+
this.hasBottomToolbar =
|
|
94
|
+
!!(set?.bottomLeft || set?.bottomRight) ||
|
|
95
|
+
['toolbar-bottom', 'toolbar-bottom-left', 'toolbar-bottom-right'].some(s => slots.has(s));
|
|
80
96
|
}
|
|
81
97
|
|
|
82
98
|
updated(changedProperties) {
|
|
83
99
|
super.updated(changedProperties);
|
|
84
|
-
if(changedProperties.has('
|
|
85
|
-
|
|
100
|
+
if (changedProperties.has('controls')) {
|
|
101
|
+
this.updateToolbarVisibility();
|
|
102
|
+
if (this.controls && this.controls !== 'none') this.loadControls();
|
|
103
|
+
}
|
|
104
|
+
if (changedProperties.has('value') && !this.skipValueSync) {
|
|
105
|
+
if (this.lexicalValueSync) {
|
|
86
106
|
this.lexicalValueSync = false;
|
|
87
107
|
} else {
|
|
88
|
-
if(this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(this.value)){
|
|
108
|
+
if (this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(this.value)) {
|
|
89
109
|
this.skipLexicalExport = true;
|
|
90
110
|
this.mode = 'code';
|
|
91
111
|
} else {
|
|
@@ -98,12 +118,17 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
98
118
|
bubbles: true
|
|
99
119
|
}));
|
|
100
120
|
}
|
|
101
|
-
if(changedProperties.has('mode')){
|
|
121
|
+
if (changedProperties.has('mode')) {
|
|
122
|
+
const scrollY = window.scrollY;
|
|
102
123
|
this.handleModeSwitch(changedProperties.get('mode'));
|
|
103
124
|
this.dispatchEvent(new CustomEvent('mode-changed', {
|
|
104
125
|
detail: { mode: this.mode },
|
|
105
126
|
bubbles: true
|
|
106
127
|
}));
|
|
128
|
+
requestAnimationFrame(() => window.scrollTo(0, scrollY));
|
|
129
|
+
}
|
|
130
|
+
if(changedProperties.has('fullscreen')){
|
|
131
|
+
requestAnimationFrame(() => this.monacoEditor?.layout());
|
|
107
132
|
}
|
|
108
133
|
}
|
|
109
134
|
|
|
@@ -120,8 +145,56 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
120
145
|
/*
|
|
121
146
|
Module Loading
|
|
122
147
|
*/
|
|
148
|
+
async loadControls() {
|
|
149
|
+
if (this.controlsLoaded) return;
|
|
150
|
+
this.controlsLoaded = true;
|
|
151
|
+
const base = new URL('./htmlEditorControls/', import.meta.url).href;
|
|
152
|
+
await Promise.all([
|
|
153
|
+
import(/* @vite-ignore */ `${base}Bold.js`),
|
|
154
|
+
import(/* @vite-ignore */ `${base}Italic.js`),
|
|
155
|
+
import(/* @vite-ignore */ `${base}Underline.js`),
|
|
156
|
+
import(/* @vite-ignore */ `${base}Strikethrough.js`),
|
|
157
|
+
import(/* @vite-ignore */ `${base}InlineCode.js`),
|
|
158
|
+
import(/* @vite-ignore */ `${base}DropdownControl.js`),
|
|
159
|
+
import(/* @vite-ignore */ `${base}FormatBlock.js`),
|
|
160
|
+
import(/* @vite-ignore */ `${base}CodeBlock.js`),
|
|
161
|
+
import(/* @vite-ignore */ `${base}BulletList.js`),
|
|
162
|
+
import(/* @vite-ignore */ `${base}NumberList.js`),
|
|
163
|
+
import(/* @vite-ignore */ `${base}AlignLeft.js`),
|
|
164
|
+
import(/* @vite-ignore */ `${base}AlignCenter.js`),
|
|
165
|
+
import(/* @vite-ignore */ `${base}AlignRight.js`),
|
|
166
|
+
import(/* @vite-ignore */ `${base}AlignJustify.js`),
|
|
167
|
+
import(/* @vite-ignore */ `${base}TextColor.js`),
|
|
168
|
+
import(/* @vite-ignore */ `${base}TextBackgroundColor.js`),
|
|
169
|
+
import(/* @vite-ignore */ `${base}ClearFormatting.js`),
|
|
170
|
+
import(/* @vite-ignore */ `${base}CreateLink.js`),
|
|
171
|
+
import(/* @vite-ignore */ `${base}InsertTable.js`),
|
|
172
|
+
import(/* @vite-ignore */ `${base}ControlGroup.js`),
|
|
173
|
+
import(/* @vite-ignore */ `${base}ControlSpacer.js`),
|
|
174
|
+
import(/* @vite-ignore */ `${base}Mode.js`),
|
|
175
|
+
import(/* @vite-ignore */ `${base}WordCount.js`),
|
|
176
|
+
import(/* @vite-ignore */ `${base}CharacterCount.js`),
|
|
177
|
+
]);
|
|
178
|
+
const cecBase = new URL('./codeEditorControls/', import.meta.url).href;
|
|
179
|
+
await Promise.all([
|
|
180
|
+
import(/* @vite-ignore */ `${cecBase}FormatCode.js`),
|
|
181
|
+
import(/* @vite-ignore */ `${cecBase}CopyCode.js`),
|
|
182
|
+
import(/* @vite-ignore */ `${cecBase}Undo.js`),
|
|
183
|
+
import(/* @vite-ignore */ `${cecBase}Redo.js`),
|
|
184
|
+
import(/* @vite-ignore */ `${cecBase}WordWrap.js`),
|
|
185
|
+
import(/* @vite-ignore */ `${cecBase}Minimap.js`),
|
|
186
|
+
import(/* @vite-ignore */ `${cecBase}FindReplace.js`),
|
|
187
|
+
import(/* @vite-ignore */ `${cecBase}FontSize.js`),
|
|
188
|
+
import(/* @vite-ignore */ `${cecBase}FoldAll.js`),
|
|
189
|
+
import(/* @vite-ignore */ `${cecBase}EditorTheme.js`),
|
|
190
|
+
import(/* @vite-ignore */ `${cecBase}Fullscreen.js`),
|
|
191
|
+
import(/* @vite-ignore */ `${cecBase}ControlGroup.js`),
|
|
192
|
+
]);
|
|
193
|
+
this.requestUpdate();
|
|
194
|
+
}
|
|
195
|
+
|
|
123
196
|
async loadNodeModules() {
|
|
124
|
-
if(!this.nodes?.trim()) return [];
|
|
197
|
+
if (!this.nodes?.trim()) return [];
|
|
125
198
|
const base = new URL('./htmlEditorNodes/', import.meta.url).href;
|
|
126
199
|
const modules = await Promise.all(
|
|
127
200
|
this.nodes.split(',').map(n => n.trim()).filter(Boolean).map(n => import(/* @vite-ignore */ `${base}${n}.js`))
|
|
@@ -130,7 +203,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
130
203
|
}
|
|
131
204
|
|
|
132
205
|
async loadLexicalModules() {
|
|
133
|
-
const base = this.lexicalSrc || DEFAULT_LEXICAL_BASE;
|
|
206
|
+
const base = this.lexicalSrc || window.kempo?.lexicalUrl || DEFAULT_LEXICAL_BASE;
|
|
134
207
|
const url = pkg => lexicalUrl(base, pkg);
|
|
135
208
|
const [lexical, richText, lexicalHtml, history, list, link, selection, table, code] = await Promise.all([
|
|
136
209
|
import(/* @vite-ignore */ url('lexical')),
|
|
@@ -152,7 +225,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
152
225
|
span: () => ({
|
|
153
226
|
conversion: domNode => {
|
|
154
227
|
const style = domNode.getAttribute('style');
|
|
155
|
-
if(!style) return null;
|
|
228
|
+
if (!style) return null;
|
|
156
229
|
const node = lexical.$createTextNode(domNode.textContent);
|
|
157
230
|
node.setStyle(style);
|
|
158
231
|
return { node };
|
|
@@ -200,15 +273,15 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
200
273
|
richText.registerRichText(this.lexicalEditor),
|
|
201
274
|
history.registerHistory(this.lexicalEditor, history.createEmptyHistoryState(), 300)
|
|
202
275
|
];
|
|
203
|
-
if(list.registerList) this.cleanupFns.push(list.registerList(this.lexicalEditor));
|
|
204
|
-
if(table.registerTable) this.cleanupFns.push(table.registerTable(this.lexicalEditor));
|
|
205
|
-
if(code.registerCodeHighlighting) this.cleanupFns.push(code.registerCodeHighlighting(this.lexicalEditor));
|
|
206
|
-
if(link.registerLink) this.cleanupFns.push(link.registerLink(this.lexicalEditor, {
|
|
276
|
+
if (list.registerList) this.cleanupFns.push(list.registerList(this.lexicalEditor));
|
|
277
|
+
if (table.registerTable) this.cleanupFns.push(table.registerTable(this.lexicalEditor));
|
|
278
|
+
if (code.registerCodeHighlighting) this.cleanupFns.push(code.registerCodeHighlighting(this.lexicalEditor));
|
|
279
|
+
if (link.registerLink) this.cleanupFns.push(link.registerLink(this.lexicalEditor, {
|
|
207
280
|
validateUrl: url => { try { new URL(url); return true; } catch { return false; } }
|
|
208
281
|
}));
|
|
209
282
|
|
|
210
|
-
if(this.value){
|
|
211
|
-
if(this.isVisualCompatible(this.value)){
|
|
283
|
+
if (this.value) {
|
|
284
|
+
if (this.isVisualCompatible(this.value)) {
|
|
212
285
|
this.importHtmlToLexical(this.value);
|
|
213
286
|
} else {
|
|
214
287
|
this.skipLexicalExport = true;
|
|
@@ -217,7 +290,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
217
290
|
}
|
|
218
291
|
|
|
219
292
|
this.lexicalEditor.registerUpdateListener(({ dirtyElements, dirtyLeaves }) => {
|
|
220
|
-
if(dirtyElements.size === 0 && dirtyLeaves.size === 0) return;
|
|
293
|
+
if (dirtyElements.size === 0 && dirtyLeaves.size === 0) return;
|
|
221
294
|
this.debouncedSyncValue();
|
|
222
295
|
this.dispatchEvent(new CustomEvent('input', {
|
|
223
296
|
detail: { value: this.exportHtmlFromLexical() },
|
|
@@ -232,14 +305,14 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
232
305
|
);
|
|
233
306
|
|
|
234
307
|
this.syncShadowSelection = () => {
|
|
235
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
308
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
236
309
|
const shadowSel = this.shadowRoot.getSelection?.();
|
|
237
|
-
if(!shadowSel || shadowSel.rangeCount === 0) return;
|
|
310
|
+
if (!shadowSel || shadowSel.rangeCount === 0) return;
|
|
238
311
|
const range = shadowSel.getRangeAt(0);
|
|
239
|
-
if(!this.lexicalContainer.contains(range.startContainer)) return;
|
|
312
|
+
if (!this.lexicalContainer.contains(range.startContainer)) return;
|
|
240
313
|
this.lexicalEditor.update(() => {
|
|
241
314
|
const lexSel = lexical.$createRangeSelectionFromDom(shadowSel, this.lexicalEditor);
|
|
242
|
-
if(lexSel) lexical.$setSelection(lexSel);
|
|
315
|
+
if (lexSel) lexical.$setSelection(lexSel);
|
|
243
316
|
}, { discrete: true });
|
|
244
317
|
this.updateSelection();
|
|
245
318
|
};
|
|
@@ -247,21 +320,21 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
247
320
|
}
|
|
248
321
|
|
|
249
322
|
async initMonaco() {
|
|
250
|
-
if(this.monacoEditor) return;
|
|
251
|
-
if(this.monacoInitPromise) return this.monacoInitPromise;
|
|
323
|
+
if (this.monacoEditor) return;
|
|
324
|
+
if (this.monacoInitPromise) return this.monacoInitPromise;
|
|
252
325
|
this.monacoInitPromise = this._initMonaco();
|
|
253
326
|
await this.monacoInitPromise;
|
|
254
327
|
this.monacoInitPromise = null;
|
|
255
328
|
}
|
|
256
329
|
|
|
257
330
|
async _initMonaco() {
|
|
258
|
-
const src = this.monacoSrc || DEFAULT_MONACO_SRC;
|
|
331
|
+
const src = this.monacoSrc || window.kempo?.monacoUrl || DEFAULT_MONACO_SRC;
|
|
259
332
|
|
|
260
333
|
await new Promise((resolve, reject) => {
|
|
261
|
-
if(window.monaco){ resolve(); return; }
|
|
262
|
-
if(window.require?.defined?.('vs/editor/editor.main')){ resolve(); return; }
|
|
334
|
+
if (window.monaco) { resolve(); return; }
|
|
335
|
+
if (window.require?.defined?.('vs/editor/editor.main')) { resolve(); return; }
|
|
263
336
|
const existing = document.querySelector(`script[src="${src}/vs/loader.js"]`);
|
|
264
|
-
if(existing){
|
|
337
|
+
if (existing) {
|
|
265
338
|
existing.addEventListener('load', () => {
|
|
266
339
|
window.require.config({ paths: { vs: `${src}/vs` } });
|
|
267
340
|
window.require(['vs/editor/editor.main'], () => resolve(), reject);
|
|
@@ -281,17 +354,18 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
281
354
|
this.monacoEditor = window.monaco.editor.create(this.monacoContainer, {
|
|
282
355
|
value: formatCode(this.value),
|
|
283
356
|
language: 'html',
|
|
284
|
-
theme:
|
|
285
|
-
minimap: { enabled:
|
|
286
|
-
wordWrap: 'on',
|
|
287
|
-
fontSize:
|
|
357
|
+
theme: this.resolveMonacoTheme(),
|
|
358
|
+
minimap: { enabled: this.minimapEnabled },
|
|
359
|
+
wordWrap: this.wordWrap ? 'on' : 'off',
|
|
360
|
+
fontSize: this.fontSize,
|
|
288
361
|
scrollBeyondLastLine: false,
|
|
289
362
|
automaticLayout: true,
|
|
290
|
-
tabSize: 2
|
|
363
|
+
tabSize: 2,
|
|
364
|
+
padding: { top: 8 }
|
|
291
365
|
});
|
|
292
366
|
|
|
293
367
|
const monacoCSS = document.querySelector('link[href*="monaco"][href*="editor.main.css"]');
|
|
294
|
-
if(monacoCSS){
|
|
368
|
+
if (monacoCSS) {
|
|
295
369
|
const link = document.createElement('link');
|
|
296
370
|
link.rel = 'stylesheet';
|
|
297
371
|
link.href = monacoCSS.href;
|
|
@@ -299,7 +373,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
299
373
|
}
|
|
300
374
|
|
|
301
375
|
this.unsubscribeTheme = subscribeToTheme(() => {
|
|
302
|
-
if(this.monacoEditor) window.monaco.editor.setTheme(
|
|
376
|
+
if (this.monacoEditor && this.editorTheme === 'auto') window.monaco.editor.setTheme(this.resolveMonacoTheme());
|
|
303
377
|
});
|
|
304
378
|
|
|
305
379
|
this.monacoEditor.onDidChangeModelContent(() => {
|
|
@@ -316,21 +390,21 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
316
390
|
Content Sync
|
|
317
391
|
*/
|
|
318
392
|
importHtmlToLexical(htmlString) {
|
|
319
|
-
if(!this.lexicalEditor || !this.lx.lexicalHtml) return;
|
|
393
|
+
if (!this.lexicalEditor || !this.lx.lexicalHtml) return;
|
|
320
394
|
const { lexical, lexicalHtml } = this.lx;
|
|
321
395
|
const processed = (this.nodePreprocessors || []).reduce((str, fn) => fn(str), htmlString);
|
|
322
396
|
this.lexicalEditor.update(() => {
|
|
323
397
|
const root = lexical.$getRoot();
|
|
324
398
|
root.clear();
|
|
325
|
-
if(!processed?.trim()) return;
|
|
399
|
+
if (!processed?.trim()) return;
|
|
326
400
|
const dom = new DOMParser().parseFromString(processed, 'text/html');
|
|
327
401
|
const nodes = lexicalHtml.$generateNodesFromDOM(this.lexicalEditor, dom);
|
|
328
|
-
if(nodes.length > 0) lexical.$insertNodes(nodes);
|
|
402
|
+
if (nodes.length > 0) lexical.$insertNodes(nodes);
|
|
329
403
|
}, { discrete: true });
|
|
330
404
|
}
|
|
331
405
|
|
|
332
406
|
exportHtmlFromLexical() {
|
|
333
|
-
if(!this.lexicalEditor || !this.lx.lexicalHtml) return this.value;
|
|
407
|
+
if (!this.lexicalEditor || !this.lx.lexicalHtml) return this.value;
|
|
334
408
|
let result = '';
|
|
335
409
|
this.lexicalEditor.getEditorState().read(() => {
|
|
336
410
|
result = this.lx.lexicalHtml.$generateHtmlFromNodes(this.lexicalEditor, null);
|
|
@@ -339,16 +413,16 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
339
413
|
}
|
|
340
414
|
|
|
341
415
|
isVisualCompatible(htmlStr) {
|
|
342
|
-
if(!htmlStr?.trim()) return true;
|
|
416
|
+
if (!htmlStr?.trim()) return true;
|
|
343
417
|
const incompatibleTags = new Set(['script', 'style', 'meta', 'link', 'head', 'iframe', 'object', 'embed', 'canvas', 'video', 'audio', 'form', 'input', 'button', 'select', 'textarea', 'fieldset', 'label', 'noscript', 'template', 'slot', 'svg', 'math']);
|
|
344
418
|
const checkers = this.nodeCompatCheckers || [];
|
|
345
419
|
const doc = new DOMParser().parseFromString(htmlStr, 'text/html');
|
|
346
420
|
const walker = document.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);
|
|
347
421
|
let node;
|
|
348
|
-
while((node = walker.nextNode())){
|
|
349
|
-
if(checkers.some(check => check(node))) continue;
|
|
350
|
-
if(node.nodeType === Node.COMMENT_NODE) return false;
|
|
351
|
-
if(incompatibleTags.has(node.tagName?.toLowerCase())) return false;
|
|
422
|
+
while ((node = walker.nextNode())) {
|
|
423
|
+
if (checkers.some(check => check(node))) continue;
|
|
424
|
+
if (node.nodeType === Node.COMMENT_NODE) return false;
|
|
425
|
+
if (incompatibleTags.has(node.tagName?.toLowerCase())) return false;
|
|
352
426
|
}
|
|
353
427
|
return true;
|
|
354
428
|
}
|
|
@@ -357,16 +431,16 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
357
431
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
358
432
|
doc.body.querySelectorAll('[class]').forEach(el => {
|
|
359
433
|
const classes = Array.from(el.classList).filter(c => !c.startsWith('k-editor-') && c !== 'td-u' && c !== 'td-lt');
|
|
360
|
-
if(classes.length === 0) el.removeAttribute('class');
|
|
434
|
+
if (classes.length === 0) el.removeAttribute('class');
|
|
361
435
|
else el.className = classes.join(' ');
|
|
362
436
|
});
|
|
363
437
|
doc.body.querySelectorAll('[style]').forEach(el => {
|
|
364
438
|
const style = el.style.cssText.replace(/white-space:\s*pre-wrap;?\s*/g, '').trim();
|
|
365
|
-
if(!style) el.removeAttribute('style');
|
|
439
|
+
if (!style) el.removeAttribute('style');
|
|
366
440
|
else el.style.cssText = style;
|
|
367
441
|
});
|
|
368
442
|
doc.body.querySelectorAll('span:not([class]):not([style]):not([id])').forEach(span => {
|
|
369
|
-
if(!span.attributes.length) span.replaceWith(...span.childNodes);
|
|
443
|
+
if (!span.attributes.length) span.replaceWith(...span.childNodes);
|
|
370
444
|
});
|
|
371
445
|
doc.body.querySelectorAll('b > strong, i > em, b > b, strong > strong, i > i, em > em').forEach(inner => {
|
|
372
446
|
inner.replaceWith(...inner.childNodes);
|
|
@@ -379,30 +453,30 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
379
453
|
}
|
|
380
454
|
|
|
381
455
|
syncValueFromLexical() {
|
|
382
|
-
if(!this.lexicalEditor) return;
|
|
456
|
+
if (!this.lexicalEditor) return;
|
|
383
457
|
this.lexicalValueSync = true;
|
|
384
458
|
this.value = this.exportHtmlFromLexical();
|
|
385
459
|
this.updateFormValue();
|
|
386
460
|
}
|
|
387
461
|
|
|
388
462
|
syncContentToEditors() {
|
|
389
|
-
if(this.mode === 'visual' && this.lexicalEditor){
|
|
463
|
+
if (this.mode === 'visual' && this.lexicalEditor) {
|
|
390
464
|
this.importHtmlToLexical(this.value);
|
|
391
465
|
}
|
|
392
466
|
}
|
|
393
467
|
|
|
394
468
|
async handleModeSwitch(previousMode) {
|
|
395
|
-
if(this.mode === 'code'){
|
|
396
|
-
if(this.lexicalEditor && !this.skipLexicalExport) this.value = this.exportHtmlFromLexical();
|
|
469
|
+
if (this.mode === 'code') {
|
|
470
|
+
if (this.lexicalEditor && !this.skipLexicalExport) this.value = this.exportHtmlFromLexical();
|
|
397
471
|
this.skipLexicalExport = false;
|
|
398
472
|
await this.initMonaco();
|
|
399
|
-
if(this.monacoEditor){
|
|
473
|
+
if (this.monacoEditor) {
|
|
400
474
|
this.monacoEditor.setValue(formatCode(this.value));
|
|
401
475
|
this.monacoEditor.layout();
|
|
402
476
|
}
|
|
403
|
-
} else if(this.mode === 'visual'){
|
|
404
|
-
if(this.monacoEditor) this.value = this.monacoEditor.getValue();
|
|
405
|
-
if(this.lexicalEditor) this.importHtmlToLexical(this.value);
|
|
477
|
+
} else if (this.mode === 'visual') {
|
|
478
|
+
if (this.monacoEditor) this.value = this.monacoEditor.getValue();
|
|
479
|
+
if (this.lexicalEditor) this.importHtmlToLexical(this.value);
|
|
406
480
|
}
|
|
407
481
|
this.requestUpdate();
|
|
408
482
|
}
|
|
@@ -426,14 +500,14 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
426
500
|
Selection Management
|
|
427
501
|
*/
|
|
428
502
|
updateSelection = () => {
|
|
429
|
-
if(this.mode !== 'visual' || !this.lexicalEditor){
|
|
503
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) {
|
|
430
504
|
this.selection = null;
|
|
431
505
|
return;
|
|
432
506
|
}
|
|
433
507
|
const { lexical } = this.lx;
|
|
434
508
|
this.lexicalEditor.getEditorState().read(() => {
|
|
435
509
|
const sel = lexical.$getSelection();
|
|
436
|
-
if(lexical.$isRangeSelection(sel) && !sel.isCollapsed()){
|
|
510
|
+
if (lexical.$isRangeSelection(sel) && !sel.isCollapsed()) {
|
|
437
511
|
this.selection = { text: sel.getTextContent(), collapsed: false };
|
|
438
512
|
} else {
|
|
439
513
|
this.selection = null;
|
|
@@ -446,11 +520,11 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
446
520
|
Public Methods - Mode Control
|
|
447
521
|
*/
|
|
448
522
|
setMode(mode) {
|
|
449
|
-
if(!['visual', 'code'].includes(mode)) return this;
|
|
450
|
-
if(mode === 'visual' && !this.isVisualCompatible(this.getValue())){
|
|
523
|
+
if (!['visual', 'code'].includes(mode)) return this;
|
|
524
|
+
if (mode === 'visual' && !this.isVisualCompatible(this.getValue())) {
|
|
451
525
|
Dialog.confirm(
|
|
452
526
|
'This html contains code that is not compatible with the visual editor, the incompatible code will be lost',
|
|
453
|
-
response => { if(response) this.mode = mode; },
|
|
527
|
+
response => { if (response) this.mode = mode; },
|
|
454
528
|
{ title: 'Warning', confirmText: 'Change Anyways' }
|
|
455
529
|
);
|
|
456
530
|
return this;
|
|
@@ -467,18 +541,18 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
467
541
|
Public Methods - Content Management
|
|
468
542
|
*/
|
|
469
543
|
getValue() {
|
|
470
|
-
if(this.mode === 'visual' && this.lexicalEditor){
|
|
544
|
+
if (this.mode === 'visual' && this.lexicalEditor) {
|
|
471
545
|
this.skipValueSync = true;
|
|
472
546
|
this.value = this.exportHtmlFromLexical();
|
|
473
547
|
this.skipValueSync = false;
|
|
474
|
-
} else if(this.mode === 'code' && this.monacoEditor){
|
|
548
|
+
} else if (this.mode === 'code' && this.monacoEditor) {
|
|
475
549
|
return this.monacoEditor.getValue();
|
|
476
550
|
}
|
|
477
551
|
return this.value;
|
|
478
552
|
}
|
|
479
553
|
|
|
480
554
|
setValue(htmlStr) {
|
|
481
|
-
if(this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(htmlStr)){
|
|
555
|
+
if (this.lexicalEditor && this.mode === 'visual' && !this.isVisualCompatible(htmlStr)) {
|
|
482
556
|
this.value = htmlStr;
|
|
483
557
|
this.skipLexicalExport = true;
|
|
484
558
|
this.mode = 'code';
|
|
@@ -487,8 +561,8 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
487
561
|
}
|
|
488
562
|
this.skipValueSync = true;
|
|
489
563
|
this.value = htmlStr;
|
|
490
|
-
if(this.mode === 'visual') this.syncContentToEditors();
|
|
491
|
-
else if(this.mode === 'code' && this.monacoEditor) this.monacoEditor.setValue(formatCode(htmlStr));
|
|
564
|
+
if (this.mode === 'visual') this.syncContentToEditors();
|
|
565
|
+
else if (this.mode === 'code' && this.monacoEditor) this.monacoEditor.setValue(formatCode(htmlStr));
|
|
492
566
|
this.updateFormValue();
|
|
493
567
|
this.skipValueSync = false;
|
|
494
568
|
return this;
|
|
@@ -521,11 +595,16 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
521
595
|
return this;
|
|
522
596
|
}
|
|
523
597
|
|
|
598
|
+
inlineCode() {
|
|
599
|
+
this.lexicalFormat('code');
|
|
600
|
+
return this;
|
|
601
|
+
}
|
|
602
|
+
|
|
524
603
|
/*
|
|
525
604
|
Public Methods - Lists
|
|
526
605
|
*/
|
|
527
606
|
orderedList() {
|
|
528
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
607
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
529
608
|
this.lexicalEditor.update(() => {
|
|
530
609
|
this.lx.list.$insertList('number');
|
|
531
610
|
}, { discrete: true });
|
|
@@ -533,7 +612,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
533
612
|
}
|
|
534
613
|
|
|
535
614
|
unorderedList() {
|
|
536
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
615
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
537
616
|
this.lexicalEditor.update(() => {
|
|
538
617
|
this.lx.list.$insertList('bullet');
|
|
539
618
|
}, { discrete: true });
|
|
@@ -567,44 +646,44 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
567
646
|
Public Methods - Text Color
|
|
568
647
|
*/
|
|
569
648
|
setTextColor(color) {
|
|
570
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
649
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
571
650
|
const { lexical, selection } = this.lx;
|
|
572
651
|
this.lexicalEditor.update(() => {
|
|
573
652
|
const sel = lexical.$getSelection();
|
|
574
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
653
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
575
654
|
selection.$patchStyleText(sel, { color });
|
|
576
655
|
}, { discrete: true });
|
|
577
656
|
return this;
|
|
578
657
|
}
|
|
579
658
|
|
|
580
659
|
removeTextColor() {
|
|
581
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
660
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
582
661
|
const { lexical, selection } = this.lx;
|
|
583
662
|
this.lexicalEditor.update(() => {
|
|
584
663
|
const sel = lexical.$getSelection();
|
|
585
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
664
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
586
665
|
selection.$patchStyleText(sel, { color: null });
|
|
587
666
|
}, { discrete: true });
|
|
588
667
|
return this;
|
|
589
668
|
}
|
|
590
669
|
|
|
591
670
|
setTextBackgroundColor(color) {
|
|
592
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
671
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
593
672
|
const { lexical, selection } = this.lx;
|
|
594
673
|
this.lexicalEditor.update(() => {
|
|
595
674
|
const sel = lexical.$getSelection();
|
|
596
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
675
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
597
676
|
selection.$patchStyleText(sel, { 'background-color': color });
|
|
598
677
|
}, { discrete: true });
|
|
599
678
|
return this;
|
|
600
679
|
}
|
|
601
680
|
|
|
602
681
|
removeTextBackgroundColor() {
|
|
603
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
682
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
604
683
|
const { lexical, selection } = this.lx;
|
|
605
684
|
this.lexicalEditor.update(() => {
|
|
606
685
|
const sel = lexical.$getSelection();
|
|
607
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
686
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
608
687
|
selection.$patchStyleText(sel, { 'background-color': null });
|
|
609
688
|
}, { discrete: true });
|
|
610
689
|
return this;
|
|
@@ -614,13 +693,13 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
614
693
|
Public Methods - Formatting Control
|
|
615
694
|
*/
|
|
616
695
|
removeFormat() {
|
|
617
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
696
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
618
697
|
const { lexical, selection } = this.lx;
|
|
619
698
|
this.lexicalEditor.update(() => {
|
|
620
699
|
const sel = lexical.$getSelection();
|
|
621
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
700
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
622
701
|
sel.getNodes().forEach(node => {
|
|
623
|
-
if(lexical.$isTextNode(node)) node.setFormat(0);
|
|
702
|
+
if (lexical.$isTextNode(node)) node.setFormat(0);
|
|
624
703
|
});
|
|
625
704
|
selection.$patchStyleText(sel, { color: null, 'background-color': null });
|
|
626
705
|
}, { discrete: true });
|
|
@@ -628,29 +707,29 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
628
707
|
}
|
|
629
708
|
|
|
630
709
|
formatBlock(tag) {
|
|
631
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
710
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
632
711
|
const { lexical, richText, code } = this.lx;
|
|
633
712
|
this.lexicalEditor.update(() => {
|
|
634
713
|
const sel = lexical.$getSelection();
|
|
635
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
714
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
636
715
|
const anchor = sel.anchor.getNode();
|
|
637
716
|
const topLevel = anchor.getTopLevelElementOrThrow();
|
|
638
717
|
const isCodeNode = code.$isCodeNode(topLevel);
|
|
639
718
|
|
|
640
719
|
let newBlock;
|
|
641
|
-
if(tag === 'p'){
|
|
720
|
+
if (tag === 'p') {
|
|
642
721
|
newBlock = lexical.$createParagraphNode();
|
|
643
|
-
} else if(tag.match(/^h[1-6]$/)){
|
|
722
|
+
} else if (tag.match(/^h[1-6]$/)) {
|
|
644
723
|
newBlock = richText.$createHeadingNode(tag);
|
|
645
|
-
} else if(tag === 'blockquote'){
|
|
724
|
+
} else if (tag === 'blockquote') {
|
|
646
725
|
newBlock = richText.$createQuoteNode();
|
|
647
|
-
} else if(tag === 'pre'){
|
|
726
|
+
} else if (tag === 'pre') {
|
|
648
727
|
newBlock = code.$createCodeNode();
|
|
649
728
|
} else {
|
|
650
729
|
return;
|
|
651
730
|
}
|
|
652
731
|
|
|
653
|
-
if(isCodeNode && tag !== 'pre'){
|
|
732
|
+
if (isCodeNode && tag !== 'pre') {
|
|
654
733
|
const text = topLevel.getTextContent();
|
|
655
734
|
topLevel.replace(newBlock);
|
|
656
735
|
newBlock.append(lexical.$createTextNode(text));
|
|
@@ -664,8 +743,68 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
664
743
|
return this;
|
|
665
744
|
}
|
|
666
745
|
|
|
746
|
+
isSelectionInCodeBlock() {
|
|
747
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return false;
|
|
748
|
+
let result = false;
|
|
749
|
+
const { lexical, code } = this.lx;
|
|
750
|
+
this.lexicalEditor.getEditorState().read(() => {
|
|
751
|
+
const sel = lexical.$getSelection();
|
|
752
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
753
|
+
result = code.$isCodeNode(sel.anchor.getNode().getTopLevelElementOrThrow());
|
|
754
|
+
});
|
|
755
|
+
return result;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
getTableAtSelection() {
|
|
759
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return null;
|
|
760
|
+
let result = null;
|
|
761
|
+
const { lexical, table } = this.lx;
|
|
762
|
+
this.lexicalEditor.getEditorState().read(() => {
|
|
763
|
+
const sel = lexical.$getSelection();
|
|
764
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
765
|
+
let node = sel.anchor.getNode();
|
|
766
|
+
while (node) {
|
|
767
|
+
if (table.$isTableNode(node)) {
|
|
768
|
+
const rows = node.getChildren();
|
|
769
|
+
const cellData = [];
|
|
770
|
+
let hasHeaders = false;
|
|
771
|
+
let cols = 0;
|
|
772
|
+
rows.forEach((row, rowIndex) => {
|
|
773
|
+
const rowData = [];
|
|
774
|
+
row.getChildren().forEach(cell => {
|
|
775
|
+
if (rowIndex === 0 && table.$isTableCellNode(cell) && cell.getHeaderStyles() === table.TableCellHeaderStates.ROW) hasHeaders = true;
|
|
776
|
+
rowData.push(cell.getTextContent());
|
|
777
|
+
});
|
|
778
|
+
if (rowData.length > cols) cols = rowData.length;
|
|
779
|
+
cellData.push(rowData);
|
|
780
|
+
});
|
|
781
|
+
result = {
|
|
782
|
+
key: node.getKey(),
|
|
783
|
+
rows: hasHeaders ? rows.length - 1 : rows.length,
|
|
784
|
+
cols,
|
|
785
|
+
hasHeaders,
|
|
786
|
+
cellData
|
|
787
|
+
};
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
node = node.getParent();
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
return result;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
removeTableByKey(key) {
|
|
797
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
798
|
+
const { lexical } = this.lx;
|
|
799
|
+
this.lexicalEditor.update(() => {
|
|
800
|
+
const node = lexical.$getNodeByKey(key);
|
|
801
|
+
if (node) node.remove();
|
|
802
|
+
}, { discrete: true });
|
|
803
|
+
return this;
|
|
804
|
+
}
|
|
805
|
+
|
|
667
806
|
insertHTML(htmlStr) {
|
|
668
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
807
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
669
808
|
const { lexical, lexicalHtml } = this.lx;
|
|
670
809
|
this.lexicalEditor.update(() => {
|
|
671
810
|
const dom = new DOMParser().parseFromString(htmlStr, 'text/html');
|
|
@@ -680,14 +819,14 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
680
819
|
}
|
|
681
820
|
|
|
682
821
|
insertTable(rows, columns, includeHeaders = false, cellData = null) {
|
|
683
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
822
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
684
823
|
const { lexical, table } = this.lx;
|
|
685
824
|
this.lexicalEditor.update(() => {
|
|
686
825
|
const totalRows = rows + (includeHeaders ? 1 : 0);
|
|
687
826
|
const rowNodes = [];
|
|
688
|
-
for(let r = 0; r < totalRows; r++){
|
|
827
|
+
for (let r = 0; r < totalRows; r++) {
|
|
689
828
|
const cells = [];
|
|
690
|
-
for(let c = 0; c < columns; c++){
|
|
829
|
+
for (let c = 0; c < columns; c++) {
|
|
691
830
|
const isHeader = includeHeaders && r === 0;
|
|
692
831
|
const headerState = isHeader ? table.TableCellHeaderStates.ROW : table.TableCellHeaderStates.NO_STATUS;
|
|
693
832
|
const cell = table.$createTableCellNode(headerState);
|
|
@@ -701,7 +840,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
701
840
|
}
|
|
702
841
|
const tableNode = table.$createTableNode().append(...rowNodes);
|
|
703
842
|
const sel = lexical.$getSelection();
|
|
704
|
-
if(lexical.$isRangeSelection(sel)){
|
|
843
|
+
if (lexical.$isRangeSelection(sel)) {
|
|
705
844
|
const anchor = sel.anchor.getNode();
|
|
706
845
|
const topLevel = anchor.getTopLevelElementOrThrow();
|
|
707
846
|
topLevel.insertAfter(tableNode);
|
|
@@ -722,11 +861,11 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
722
861
|
}
|
|
723
862
|
|
|
724
863
|
replaceSelectionWithElement(element) {
|
|
725
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
864
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
726
865
|
const { lexical, lexicalHtml } = this.lx;
|
|
727
866
|
this.lexicalEditor.update(() => {
|
|
728
867
|
const sel = lexical.$getSelection();
|
|
729
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
868
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
730
869
|
sel.removeText();
|
|
731
870
|
const dom = new DOMParser().parseFromString(element.outerHTML, 'text/html');
|
|
732
871
|
const nodes = lexicalHtml.$generateNodesFromDOM(this.lexicalEditor, dom);
|
|
@@ -736,9 +875,9 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
736
875
|
}
|
|
737
876
|
|
|
738
877
|
wrapSelection(before, after, savedSelection = null) {
|
|
739
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
878
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
740
879
|
const text = savedSelection || this.getSelectedText();
|
|
741
|
-
if(!text) return this;
|
|
880
|
+
if (!text) return this;
|
|
742
881
|
return this.insertHTML(before + text + after);
|
|
743
882
|
}
|
|
744
883
|
|
|
@@ -746,12 +885,12 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
746
885
|
Public Methods - Selection Management
|
|
747
886
|
*/
|
|
748
887
|
getSelection() {
|
|
749
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return null;
|
|
888
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return null;
|
|
750
889
|
let result = null;
|
|
751
890
|
const { lexical } = this.lx;
|
|
752
891
|
this.lexicalEditor.getEditorState().read(() => {
|
|
753
892
|
const sel = lexical.$getSelection();
|
|
754
|
-
if(!lexical.$isRangeSelection(sel) || sel.isCollapsed()) return;
|
|
893
|
+
if (!lexical.$isRangeSelection(sel) || sel.isCollapsed()) return;
|
|
755
894
|
result = { text: sel.getTextContent(), html: sel.getTextContent(), selection: sel };
|
|
756
895
|
});
|
|
757
896
|
return result;
|
|
@@ -759,11 +898,11 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
759
898
|
|
|
760
899
|
getSelectedText() {
|
|
761
900
|
let text = '';
|
|
762
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return text;
|
|
901
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return text;
|
|
763
902
|
const { lexical } = this.lx;
|
|
764
903
|
this.lexicalEditor.getEditorState().read(() => {
|
|
765
904
|
const sel = lexical.$getSelection();
|
|
766
|
-
if(lexical.$isRangeSelection(sel)) text = sel.getTextContent();
|
|
905
|
+
if (lexical.$isRangeSelection(sel)) text = sel.getTextContent();
|
|
767
906
|
});
|
|
768
907
|
return text;
|
|
769
908
|
}
|
|
@@ -773,14 +912,14 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
773
912
|
}
|
|
774
913
|
|
|
775
914
|
selectAll() {
|
|
776
|
-
if(this.mode === 'visual' && this.lexicalEditor){
|
|
915
|
+
if (this.mode === 'visual' && this.lexicalEditor) {
|
|
777
916
|
const { lexical } = this.lx;
|
|
778
917
|
this.lexicalEditor.update(() => {
|
|
779
918
|
lexical.$selectAll();
|
|
780
919
|
}, { discrete: true });
|
|
781
|
-
} else if(this.monacoEditor){
|
|
920
|
+
} else if (this.monacoEditor) {
|
|
782
921
|
const model = this.monacoEditor.getModel();
|
|
783
|
-
if(model) this.monacoEditor.setSelection(model.getFullModelRange());
|
|
922
|
+
if (model) this.monacoEditor.setSelection(model.getFullModelRange());
|
|
784
923
|
}
|
|
785
924
|
return this;
|
|
786
925
|
}
|
|
@@ -790,24 +929,24 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
790
929
|
}
|
|
791
930
|
|
|
792
931
|
deleteSelection() {
|
|
793
|
-
if(this.mode === 'visual'){
|
|
932
|
+
if (this.mode === 'visual') {
|
|
794
933
|
this.lexicalCmd('DELETE_CHARACTER_COMMAND', false);
|
|
795
|
-
} else if(this.monacoEditor){
|
|
934
|
+
} else if (this.monacoEditor) {
|
|
796
935
|
this.monacoEditor.trigger('keyboard', 'deleteAllLeft', null);
|
|
797
936
|
}
|
|
798
937
|
return this;
|
|
799
938
|
}
|
|
800
939
|
|
|
801
940
|
getValueWithSelectionMarkers() {
|
|
802
|
-
if(this.mode !== 'visual' || !this.lexicalEditor){
|
|
941
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) {
|
|
803
942
|
return { html: this.value, hasCursor: false, hasSelection: false, selectedText: '' };
|
|
804
943
|
}
|
|
805
944
|
let result = { html: this.exportHtmlFromLexical(), hasCursor: false, hasSelection: false, selectedText: '' };
|
|
806
945
|
const { lexical } = this.lx;
|
|
807
946
|
this.lexicalEditor.getEditorState().read(() => {
|
|
808
947
|
const sel = lexical.$getSelection();
|
|
809
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
810
|
-
if(sel.isCollapsed()){
|
|
948
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
949
|
+
if (sel.isCollapsed()) {
|
|
811
950
|
result.hasCursor = true;
|
|
812
951
|
} else {
|
|
813
952
|
result.hasSelection = true;
|
|
@@ -837,7 +976,7 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
837
976
|
Public Methods - Links and Media
|
|
838
977
|
*/
|
|
839
978
|
createLink(url) {
|
|
840
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
979
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
841
980
|
const { link } = this.lx;
|
|
842
981
|
this.lexicalEditor.update(() => {
|
|
843
982
|
link.$toggleLink(url);
|
|
@@ -846,11 +985,11 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
846
985
|
}
|
|
847
986
|
|
|
848
987
|
createLinkWithText(url, text) {
|
|
849
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
988
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
850
989
|
const { lexical, link } = this.lx;
|
|
851
990
|
this.lexicalEditor.update(() => {
|
|
852
991
|
const sel = lexical.$getSelection();
|
|
853
|
-
if(lexical.$isRangeSelection(sel) && !sel.isCollapsed()) sel.removeText();
|
|
992
|
+
if (lexical.$isRangeSelection(sel) && !sel.isCollapsed()) sel.removeText();
|
|
854
993
|
const linkNode = link.$createLinkNode(url);
|
|
855
994
|
linkNode.append(lexical.$createTextNode(text));
|
|
856
995
|
lexical.$insertNodes([linkNode]);
|
|
@@ -859,14 +998,14 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
859
998
|
}
|
|
860
999
|
|
|
861
1000
|
unlink() {
|
|
862
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
1001
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return this;
|
|
863
1002
|
const { lexical, link } = this.lx;
|
|
864
1003
|
this.lexicalEditor.update(() => {
|
|
865
1004
|
const sel = lexical.$getSelection();
|
|
866
|
-
if(!lexical.$isRangeSelection(sel)) return;
|
|
1005
|
+
if (!lexical.$isRangeSelection(sel)) return;
|
|
867
1006
|
sel.getNodes().forEach(node => {
|
|
868
1007
|
const parent = node.getParent();
|
|
869
|
-
if(parent && link.$isLinkNode?.(parent)){
|
|
1008
|
+
if (parent && link.$isLinkNode?.(parent)) {
|
|
870
1009
|
parent.getChildren().forEach(child => parent.insertBefore(child));
|
|
871
1010
|
parent.remove();
|
|
872
1011
|
}
|
|
@@ -883,56 +1022,193 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
883
1022
|
Public Methods - History
|
|
884
1023
|
*/
|
|
885
1024
|
undo() {
|
|
886
|
-
this.
|
|
1025
|
+
if (this.mode === 'code') this.monacoEditor?.trigger('toolbar', 'undo');
|
|
1026
|
+
else this.lexicalCmd('UNDO_COMMAND', undefined);
|
|
887
1027
|
return this;
|
|
888
1028
|
}
|
|
889
1029
|
|
|
890
1030
|
redo() {
|
|
891
|
-
this.
|
|
1031
|
+
if (this.mode === 'code') this.monacoEditor?.trigger('toolbar', 'redo');
|
|
1032
|
+
else this.lexicalCmd('REDO_COMMAND', undefined);
|
|
1033
|
+
return this;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/*
|
|
1037
|
+
Public Methods - Code Editor Controls
|
|
1038
|
+
*/
|
|
1039
|
+
copyToClipboard() {
|
|
1040
|
+
navigator.clipboard.writeText(this.getValue());
|
|
1041
|
+
return this;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
setEditorTheme(theme) {
|
|
1045
|
+
if (['auto', 'light', 'dark'].includes(theme)) this.editorTheme = theme;
|
|
1046
|
+
if (this.monacoEditor) window.monaco.editor.setTheme(this.resolveMonacoTheme());
|
|
1047
|
+
return this;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
openFind() {
|
|
1051
|
+
this.monacoEditor?.getAction('actions.find')?.run();
|
|
1052
|
+
return this;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
foldAll() {
|
|
1056
|
+
this.monacoEditor?.getAction('editor.foldAll')?.run();
|
|
1057
|
+
return this;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
unfoldAll() {
|
|
1061
|
+
this.monacoEditor?.getAction('editor.unfoldAll')?.run();
|
|
1062
|
+
return this;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
enterFullscreen() {
|
|
1066
|
+
this.fullscreen = true;
|
|
1067
|
+
document.body.classList.add('no-scroll');
|
|
1068
|
+
this.dispatchEvent(new CustomEvent('fullscreen-changed', { detail: { fullscreen: true }, bubbles: true }));
|
|
1069
|
+
return this;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
exitFullscreen() {
|
|
1073
|
+
this.fullscreen = false;
|
|
1074
|
+
document.body.classList.remove('no-scroll');
|
|
1075
|
+
this.dispatchEvent(new CustomEvent('fullscreen-changed', { detail: { fullscreen: false }, bubbles: true }));
|
|
1076
|
+
return this;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
toggleFullscreen() {
|
|
1080
|
+
return this.fullscreen ? this.exitFullscreen() : this.enterFullscreen();
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
increaseFontSize() {
|
|
1084
|
+
this.fontSize = Math.min(this.fontSize + 2, 40);
|
|
1085
|
+
this.monacoEditor?.updateOptions({ fontSize: this.fontSize });
|
|
1086
|
+
return this;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
decreaseFontSize() {
|
|
1090
|
+
this.fontSize = Math.max(this.fontSize - 2, 8);
|
|
1091
|
+
this.monacoEditor?.updateOptions({ fontSize: this.fontSize });
|
|
1092
|
+
return this;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
setWordWrap(enabled) {
|
|
1096
|
+
this.wordWrap = enabled;
|
|
1097
|
+
this.monacoEditor?.updateOptions({ wordWrap: enabled ? 'on' : 'off' });
|
|
1098
|
+
return this;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
setMinimap(enabled) {
|
|
1102
|
+
this.minimapEnabled = enabled;
|
|
1103
|
+
this.monacoEditor?.updateOptions({ minimap: { enabled } });
|
|
892
1104
|
return this;
|
|
893
1105
|
}
|
|
894
1106
|
|
|
1107
|
+
resolveMonacoTheme() {
|
|
1108
|
+
if (this.editorTheme === 'dark') return 'vs-dark';
|
|
1109
|
+
if (this.editorTheme === 'light') return 'vs';
|
|
1110
|
+
return getCalculatedTheme() === 'dark' ? 'vs-dark' : 'vs';
|
|
1111
|
+
}
|
|
1112
|
+
|
|
895
1113
|
/*
|
|
896
1114
|
Utility Methods
|
|
897
1115
|
*/
|
|
898
1116
|
lexicalCmd(commandName, payload) {
|
|
899
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
1117
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
900
1118
|
const cmd = this.lx.lexical?.[commandName];
|
|
901
|
-
if(cmd) this.lexicalEditor.dispatchCommand(cmd, payload);
|
|
1119
|
+
if (cmd) this.lexicalEditor.dispatchCommand(cmd, payload);
|
|
902
1120
|
}
|
|
903
1121
|
|
|
904
1122
|
lexicalFormat(format) {
|
|
905
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
1123
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
906
1124
|
const { lexical } = this.lx;
|
|
907
1125
|
this.lexicalEditor.update(() => {
|
|
908
1126
|
const sel = lexical.$getSelection();
|
|
909
|
-
if(lexical.$isRangeSelection(sel)) sel.formatText(format);
|
|
1127
|
+
if (lexical.$isRangeSelection(sel)) sel.formatText(format);
|
|
910
1128
|
}, { discrete: true });
|
|
911
1129
|
}
|
|
912
1130
|
|
|
913
1131
|
lexicalFormatElement(alignment) {
|
|
914
|
-
if(this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
1132
|
+
if (this.mode !== 'visual' || !this.lexicalEditor) return;
|
|
915
1133
|
this.lexicalEditor.dispatchCommand(this.lx.lexical.FORMAT_ELEMENT_COMMAND, alignment);
|
|
916
1134
|
}
|
|
917
1135
|
|
|
918
1136
|
/*
|
|
919
1137
|
Rendering
|
|
920
1138
|
*/
|
|
1139
|
+
render() {
|
|
1140
|
+
const set = this.constructor.controlSets[this.controls] ?? {};
|
|
1141
|
+
return html`
|
|
1142
|
+
${this.hasTopToolbar ? html`
|
|
1143
|
+
<div class="toolbar-top bb">
|
|
1144
|
+
<div class="toolbar-start">
|
|
1145
|
+
<slot name="toolbar-top-left">${set.topLeft ?? ''}</slot>
|
|
1146
|
+
</div>
|
|
1147
|
+
<div class="toolbar-end">
|
|
1148
|
+
<slot name="toolbar-top-right">${set.topRight ?? ''}</slot>
|
|
1149
|
+
</div>
|
|
1150
|
+
</div>
|
|
1151
|
+
` : ''}
|
|
1152
|
+
<div class="editor-container">
|
|
1153
|
+
<div
|
|
1154
|
+
class="lexical-editor"
|
|
1155
|
+
contenteditable="true"
|
|
1156
|
+
?hidden=${this.mode !== 'visual'}
|
|
1157
|
+
></div>
|
|
1158
|
+
<div
|
|
1159
|
+
class="monaco-editor-container"
|
|
1160
|
+
?hidden=${this.mode !== 'code'}
|
|
1161
|
+
></div>
|
|
1162
|
+
</div>
|
|
1163
|
+
${this.hasBottomToolbar ? html`
|
|
1164
|
+
<div class="toolbar-bottom bt">
|
|
1165
|
+
<div class="toolbar-start">
|
|
1166
|
+
<slot name="toolbar-bottom-left">${set.bottomLeft ?? ''}</slot>
|
|
1167
|
+
</div>
|
|
1168
|
+
<div class="toolbar-end">
|
|
1169
|
+
<slot name="toolbar-bottom-right">${set.bottomRight ?? ''}</slot>
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1172
|
+
` : ''}
|
|
1173
|
+
`;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
|
|
921
1177
|
static styles = css`
|
|
922
1178
|
:host {
|
|
923
1179
|
display: flex;
|
|
924
1180
|
flex-direction: column;
|
|
925
1181
|
gap: 0;
|
|
926
|
-
height:
|
|
1182
|
+
height: 400px;
|
|
1183
|
+
background: var(--c_bg, rgb(249, 249, 249));
|
|
1184
|
+
}
|
|
1185
|
+
:host([fullscreen]) {
|
|
1186
|
+
position: fixed;
|
|
1187
|
+
top: 0;
|
|
1188
|
+
left: 0;
|
|
1189
|
+
width: 100vw !important;
|
|
1190
|
+
height: 100vh !important;
|
|
1191
|
+
z-index: 10000;
|
|
927
1192
|
}
|
|
928
1193
|
.toolbar-top,
|
|
929
1194
|
.toolbar-bottom {
|
|
930
1195
|
display: flex;
|
|
931
|
-
flex-wrap: wrap;
|
|
932
1196
|
align-items: center;
|
|
933
|
-
gap: 0;
|
|
934
1197
|
background: var(--bg-secondary);
|
|
935
1198
|
min-height: 40px;
|
|
1199
|
+
width: 100%;
|
|
1200
|
+
}
|
|
1201
|
+
.toolbar-start {
|
|
1202
|
+
display: flex;
|
|
1203
|
+
flex-wrap: wrap;
|
|
1204
|
+
align-items: center;
|
|
1205
|
+
}
|
|
1206
|
+
.toolbar-end {
|
|
1207
|
+
display: flex;
|
|
1208
|
+
flex-wrap: wrap-reverse;
|
|
1209
|
+
align-items: center;
|
|
1210
|
+
justify-content: flex-end;
|
|
1211
|
+
margin-left: auto;
|
|
936
1212
|
}
|
|
937
1213
|
.editor-container {
|
|
938
1214
|
position: relative;
|
|
@@ -1006,36 +1282,135 @@ export default class HtmlEditor extends ShadowComponent {
|
|
|
1006
1282
|
.monaco-editor-container {
|
|
1007
1283
|
border: 1px solid var(--border-color);
|
|
1008
1284
|
}
|
|
1009
|
-
[hidden] {
|
|
1010
|
-
display: none !important;
|
|
1011
|
-
}
|
|
1012
1285
|
`;
|
|
1013
1286
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1287
|
+
/*
|
|
1288
|
+
Static Properties
|
|
1289
|
+
*/
|
|
1290
|
+
static controlSets = {
|
|
1291
|
+
minimal: {
|
|
1292
|
+
topLeft: html`
|
|
1293
|
+
<k-hec-group>
|
|
1294
|
+
<k-hec-bold></k-hec-bold>
|
|
1295
|
+
<k-hec-italic></k-hec-italic>
|
|
1296
|
+
<k-hec-underline></k-hec-underline>
|
|
1297
|
+
</k-hec-group>
|
|
1298
|
+
<k-hec-group>
|
|
1299
|
+
<k-hec-bullet-list></k-hec-bullet-list>
|
|
1300
|
+
<k-hec-number-list></k-hec-number-list>
|
|
1301
|
+
</k-hec-group>
|
|
1302
|
+
`,
|
|
1303
|
+
topRight: null,
|
|
1304
|
+
bottomLeft: null,
|
|
1305
|
+
bottomRight: null,
|
|
1306
|
+
},
|
|
1307
|
+
normal: {
|
|
1308
|
+
topLeft: html`
|
|
1309
|
+
<k-hec-group>
|
|
1310
|
+
<k-hec-bold></k-hec-bold>
|
|
1311
|
+
<k-hec-italic></k-hec-italic>
|
|
1312
|
+
<k-hec-underline></k-hec-underline>
|
|
1313
|
+
<k-hec-strikethrough></k-hec-strikethrough>
|
|
1314
|
+
</k-hec-group>
|
|
1315
|
+
<k-hec-inline-code></k-hec-inline-code>
|
|
1316
|
+
<k-hec-dropdown>
|
|
1317
|
+
<k-icon slot="icon" name="format_paragraph"></k-icon>
|
|
1318
|
+
<span slot="label">Text Style</span>
|
|
1319
|
+
<k-hec-format-block tag="p">Paragraph</k-hec-format-block>
|
|
1320
|
+
<k-hec-format-block tag="h1">Heading 1</k-hec-format-block>
|
|
1321
|
+
<k-hec-format-block tag="h2">Heading 2</k-hec-format-block>
|
|
1322
|
+
<k-hec-format-block tag="h3">Heading 3</k-hec-format-block>
|
|
1323
|
+
<k-hec-format-block tag="blockquote">Blockquote</k-hec-format-block>
|
|
1324
|
+
<k-hec-code-block></k-hec-code-block>
|
|
1325
|
+
</k-hec-dropdown>
|
|
1326
|
+
<k-hec-group>
|
|
1327
|
+
<k-hec-bullet-list></k-hec-bullet-list>
|
|
1328
|
+
<k-hec-number-list></k-hec-number-list>
|
|
1329
|
+
</k-hec-group>
|
|
1330
|
+
`,
|
|
1331
|
+
topRight: html`
|
|
1332
|
+
<k-hec-group>
|
|
1333
|
+
<k-hec-align-left></k-hec-align-left>
|
|
1334
|
+
<k-hec-align-center></k-hec-align-center>
|
|
1335
|
+
<k-hec-align-right></k-hec-align-right>
|
|
1336
|
+
</k-hec-group>
|
|
1337
|
+
<k-hec-create-link></k-hec-create-link>
|
|
1338
|
+
<k-cec-format-code></k-cec-format-code>
|
|
1339
|
+
<k-hec-mode></k-hec-mode>
|
|
1340
|
+
`,
|
|
1341
|
+
bottomLeft: html`<k-hec-word-count></k-hec-word-count>`,
|
|
1342
|
+
bottomRight: null,
|
|
1343
|
+
},
|
|
1344
|
+
full: {
|
|
1345
|
+
topLeft: html`
|
|
1346
|
+
<k-hec-group>
|
|
1347
|
+
<k-hec-bold></k-hec-bold>
|
|
1348
|
+
<k-hec-italic></k-hec-italic>
|
|
1349
|
+
<k-hec-underline></k-hec-underline>
|
|
1350
|
+
<k-hec-strikethrough></k-hec-strikethrough>
|
|
1351
|
+
</k-hec-group>
|
|
1352
|
+
<k-hec-inline-code></k-hec-inline-code>
|
|
1353
|
+
<k-hec-dropdown>
|
|
1354
|
+
<k-icon slot="icon" name="format_paragraph"></k-icon>
|
|
1355
|
+
<span slot="label">Text Style</span>
|
|
1356
|
+
<k-hec-format-block tag="p">Paragraph</k-hec-format-block>
|
|
1357
|
+
<k-hec-format-block tag="h1">Heading 1</k-hec-format-block>
|
|
1358
|
+
<k-hec-format-block tag="h2">Heading 2</k-hec-format-block>
|
|
1359
|
+
<k-hec-format-block tag="h3">Heading 3</k-hec-format-block>
|
|
1360
|
+
<k-hec-format-block tag="blockquote">Blockquote</k-hec-format-block>
|
|
1361
|
+
<k-hec-code-block></k-hec-code-block>
|
|
1362
|
+
</k-hec-dropdown>
|
|
1363
|
+
<k-hec-group>
|
|
1364
|
+
<k-hec-bullet-list></k-hec-bullet-list>
|
|
1365
|
+
<k-hec-number-list></k-hec-number-list>
|
|
1366
|
+
</k-hec-group>
|
|
1367
|
+
`,
|
|
1368
|
+
topRight: html`
|
|
1369
|
+
<k-hec-group>
|
|
1370
|
+
<k-hec-align-left></k-hec-align-left>
|
|
1371
|
+
<k-hec-align-center></k-hec-align-center>
|
|
1372
|
+
<k-hec-align-right></k-hec-align-right>
|
|
1373
|
+
<k-hec-align-justify></k-hec-align-justify>
|
|
1374
|
+
</k-hec-group>
|
|
1375
|
+
<k-hec-create-link></k-hec-create-link>
|
|
1376
|
+
<k-hec-group>
|
|
1377
|
+
<k-hec-text-color></k-hec-text-color>
|
|
1378
|
+
<k-hec-text-background-color></k-hec-text-background-color>
|
|
1379
|
+
</k-hec-group>
|
|
1380
|
+
<k-hec-clear-formatting></k-hec-clear-formatting>
|
|
1381
|
+
<k-hec-insert-table></k-hec-insert-table>
|
|
1382
|
+
<k-cec-group>
|
|
1383
|
+
<k-cec-undo></k-cec-undo>
|
|
1384
|
+
<k-cec-redo></k-cec-redo>
|
|
1385
|
+
</k-cec-group>
|
|
1386
|
+
<k-cec-group>
|
|
1387
|
+
<k-cec-format-code></k-cec-format-code>
|
|
1388
|
+
<k-cec-copy-code></k-cec-copy-code>
|
|
1389
|
+
<k-cec-find-replace></k-cec-find-replace>
|
|
1390
|
+
</k-cec-group>
|
|
1391
|
+
<k-cec-group>
|
|
1392
|
+
<k-cec-word-wrap></k-cec-word-wrap>
|
|
1393
|
+
<k-cec-minimap></k-cec-minimap>
|
|
1394
|
+
<k-cec-fold-all></k-cec-fold-all>
|
|
1395
|
+
</k-cec-group>
|
|
1396
|
+
<k-cec-font-size></k-cec-font-size>
|
|
1397
|
+
<k-cec-editor-theme></k-cec-editor-theme>
|
|
1398
|
+
<k-hec-mode></k-hec-mode>
|
|
1399
|
+
<k-cec-fullscreen></k-cec-fullscreen>
|
|
1400
|
+
`,
|
|
1401
|
+
bottomLeft: html`
|
|
1402
|
+
<k-hec-word-count></k-hec-word-count>
|
|
1403
|
+
<k-hec-character-count></k-hec-character-count>
|
|
1404
|
+
`,
|
|
1405
|
+
bottomRight: null,
|
|
1406
|
+
},
|
|
1407
|
+
"": {
|
|
1408
|
+
topLeft: null,
|
|
1409
|
+
topRight: null,
|
|
1410
|
+
bottomLeft: null,
|
|
1411
|
+
bottomRight: null,
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1039
1414
|
}
|
|
1040
1415
|
|
|
1041
1416
|
customElements.define('k-html-editor', HtmlEditor);
|