@bagelink/vue 1.5.15 → 1.5.20
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/bin/experimentalGenTypedRoutes.ts +15 -15
- package/bin/generateFormSchema.ts +12 -12
- package/bin/utils.ts +4 -4
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/RouterWrapper.vue.d.ts.map +1 -1
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts +5 -4
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CheckInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -0
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ToggleInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/composables/useFormField.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +68 -55
- package/dist/index.mjs +34035 -143
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/AccordionItem.vue +2 -2
- package/src/components/AddToCalendar.vue +1 -1
- package/src/components/BglVideo.vue +8 -8
- package/src/components/Btn.vue +9 -9
- package/src/components/Card.vue +4 -4
- package/src/components/Carousel.vue +44 -44
- package/src/components/DataPreview.vue +1 -1
- package/src/components/DragOver.vue +6 -6
- package/src/components/Dropdown.vue +14 -14
- package/src/components/Flag.vue +3 -3
- package/src/components/Icon/Icon.vue +13 -13
- package/src/components/Image.vue +4 -4
- package/src/components/ImportData.vue +79 -79
- package/src/components/ListItem.vue +7 -7
- package/src/components/MapEmbed/Index.vue +6 -6
- package/src/components/Modal.vue +10 -10
- package/src/components/ModalForm.vue +4 -4
- package/src/components/NavBar.vue +2 -2
- package/src/components/Pagination.vue +9 -9
- package/src/components/Pill.vue +1 -1
- package/src/components/Rating.vue +2 -2
- package/src/components/RouterWrapper.vue +3 -3
- package/src/components/Slider.vue +77 -77
- package/src/components/Spreadsheet/Index.vue +34 -34
- package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
- package/src/components/Zoomer.vue +28 -28
- package/src/components/analytics/BarChart.vue +6 -6
- package/src/components/analytics/KpiCard.vue +2 -2
- package/src/components/analytics/LineChart.vue +14 -14
- package/src/components/analytics/PieChart.vue +11 -11
- package/src/components/calendar/CalendarPopover.vue +1 -1
- package/src/components/calendar/Index.vue +1 -1
- package/src/components/calendar/views/AgendaView.vue +2 -2
- package/src/components/calendar/views/DayView.vue +6 -6
- package/src/components/calendar/views/MonthView.vue +2 -2
- package/src/components/calendar/views/WeekView.vue +18 -18
- package/src/components/dataTable/DataTable.vue +3 -3
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +15 -15
- package/src/components/dataTable/useTableSelection.ts +8 -8
- package/src/components/dataTable/useTableVirtualization.ts +1 -1
- package/src/components/draggable/useDraggable.ts +42 -42
- package/src/components/form/BagelForm.vue +66 -23
- package/src/components/form/BglMultiStepForm.vue +18 -18
- package/src/components/form/FieldArray.vue +177 -67
- package/src/components/form/inputs/CheckInput.vue +2 -1
- package/src/components/form/inputs/CodeEditor/Index.vue +1 -1
- package/src/components/form/inputs/CodeEditor/format.ts +7 -7
- package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
- package/src/components/form/inputs/DateInput.vue +6 -6
- package/src/components/form/inputs/DatePicker.vue +19 -19
- package/src/components/form/inputs/EmailInput.vue +14 -14
- package/src/components/form/inputs/NumberInput.vue +6 -6
- package/src/components/form/inputs/OTP.vue +3 -3
- package/src/components/form/inputs/RadioGroup.vue +1 -1
- package/src/components/form/inputs/RadioPillsInput.vue +8 -8
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +10 -10
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +1 -1
- package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
- package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
- package/src/components/form/inputs/RichText/index.vue +300 -132
- package/src/components/form/inputs/RichText/utils/commands.ts +69 -69
- package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
- package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
- package/src/components/form/inputs/RichText/utils/media.ts +6 -6
- package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
- package/src/components/form/inputs/RichText/utils/table.ts +19 -19
- package/src/components/form/inputs/SelectBtn.vue +1 -1
- package/src/components/form/inputs/SelectInput.vue +50 -26
- package/src/components/form/inputs/SignaturePad.vue +15 -15
- package/src/components/form/inputs/TableField.vue +1 -1
- package/src/components/form/inputs/TelInput.vue +6 -6
- package/src/components/form/inputs/TextInput.vue +5 -5
- package/src/components/form/inputs/ToggleInput.vue +2 -1
- package/src/components/form/inputs/Upload/UploadInput.vue +155 -102
- package/src/components/form/inputs/Upload/upload.ts +1 -1
- package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
- package/src/components/form/useBagelFormState.ts +5 -5
- package/src/components/layout/AppContent.vue +1 -1
- package/src/components/layout/AppLayout.vue +1 -1
- package/src/components/layout/Layout.vue +4 -4
- package/src/components/layout/TabbedLayout.vue +1 -1
- package/src/components/layout/Tabs.vue +2 -2
- package/src/components/layout/TabsNav.vue +7 -7
- package/src/components/lightbox/Lightbox.vue +8 -8
- package/src/components/lightbox/index.ts +8 -8
- package/src/composables/index.ts +2 -2
- package/src/composables/useAddToCalendar.ts +13 -13
- package/src/composables/useDevice.ts +2 -2
- package/src/composables/useExcel.ts +6 -6
- package/src/composables/useFormField.ts +5 -9
- package/src/composables/usePolling.ts +8 -8
- package/src/composables/useSchemaField.ts +53 -38
- package/src/composables/useTheme.ts +9 -9
- package/src/composables/useValidateFieldValue.ts +2 -2
- package/src/directives/pattern.ts +25 -25
- package/src/directives/ripple.ts +4 -4
- package/src/directives/vResize.ts +6 -6
- package/src/plugins/bagel.ts +4 -4
- package/src/plugins/useModal.ts +3 -3
- package/src/styles/layout.css +7 -1
- package/src/utils/BagelFormUtils.ts +7 -7
- package/src/utils/calendar/Helpers.ts +8 -8
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/utils/calendar/time.ts +25 -25
- package/src/utils/calendar/week.ts +25 -25
- package/src/utils/elementUtils.ts +27 -27
- package/src/utils/index.ts +22 -22
- package/src/utils/sizeParsing.ts +2 -2
- package/src/utils/strings.ts +5 -5
- package/src/utils/tapDetector.ts +11 -11
- package/src/utils/useSearch.ts +29 -29
- package/vite.config.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ToolbarConfig } from './richTextTypes'
|
|
3
3
|
import { CodeEditor, copyText, Btn, Modal, BglVideo, Icon, Card, ColorInput } from '@bagelink/vue'
|
|
4
|
-
import { watch, onUnmounted, onBeforeUnmount, ref, computed, useAttrs } from 'vue'
|
|
4
|
+
import { watch, onUnmounted, onBeforeUnmount, onMounted, ref, computed, useAttrs } from 'vue'
|
|
5
5
|
import CheckInput from '../CheckInput.vue'
|
|
6
6
|
import NumberInput from '../NumberInput.vue'
|
|
7
7
|
import SelectInput from '../SelectInput.vue'
|
|
@@ -41,6 +41,8 @@ const props = defineProps<{
|
|
|
41
41
|
autofocus?: boolean
|
|
42
42
|
// Text color
|
|
43
43
|
textColor?: string
|
|
44
|
+
// Font size
|
|
45
|
+
fontSize?: number | string
|
|
44
46
|
}>()
|
|
45
47
|
|
|
46
48
|
const emit = defineEmits(['update:modelValue'])
|
|
@@ -52,15 +54,111 @@ const editor = useEditor()
|
|
|
52
54
|
const isInitializing = ref(false)
|
|
53
55
|
const hasInitialized = ref(false)
|
|
54
56
|
const commands = useCommands(editor.state, editor.state.debug)
|
|
57
|
+
|
|
58
|
+
// Reactive theme colors with forced reactivity
|
|
59
|
+
const forceUpdate = ref(0)
|
|
60
|
+
const currentInputColor = computed(() => {
|
|
61
|
+
// Force reactivity by using forceUpdate
|
|
62
|
+
void forceUpdate.value
|
|
63
|
+
|
|
64
|
+
if ('undefined' !== typeof document) {
|
|
65
|
+
const computedStyle = getComputedStyle(document.documentElement)
|
|
66
|
+
const color = computedStyle.getPropertyValue('--input-color').trim()
|
|
67
|
+
console.log('🎨 currentInputColor computed:', color, 'forceUpdate:', forceUpdate.value)
|
|
68
|
+
return color || '#000'
|
|
69
|
+
}
|
|
70
|
+
return '#000'
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const currentTextColor = computed(() => {
|
|
74
|
+
const inputColor = currentInputColor.value
|
|
75
|
+
const textColor = props.textColor || (inputColor && 0 < inputColor.length && '#000' !== inputColor ? inputColor : 'inherit')
|
|
76
|
+
console.log('🎨 currentTextColor computed:', textColor, 'from inputColor:', inputColor)
|
|
77
|
+
return textColor
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// Set up theme observation with MutationObserver
|
|
81
|
+
let themeObserver: MutationObserver | null = null
|
|
82
|
+
|
|
83
|
+
onMounted(() => {
|
|
84
|
+
if ('undefined' !== typeof document) {
|
|
85
|
+
themeObserver = new MutationObserver((mutations) => {
|
|
86
|
+
let shouldUpdate = false
|
|
87
|
+
mutations.forEach((mutation) => {
|
|
88
|
+
if ('attributes' === mutation.type) {
|
|
89
|
+
const { attributeName } = mutation
|
|
90
|
+
if ('data-theme' === attributeName
|
|
91
|
+
|| 'class' === attributeName
|
|
92
|
+
|| 'style' === attributeName) {
|
|
93
|
+
shouldUpdate = true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
if (shouldUpdate) {
|
|
99
|
+
console.log('🔄 Theme change detected, forcing update')
|
|
100
|
+
forceUpdate.value++
|
|
101
|
+
|
|
102
|
+
// Also directly update iframe if initialized
|
|
103
|
+
if (hasInitialized.value) {
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
updateIframeColors()
|
|
106
|
+
}, 50)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
// Watch for attribute changes on document element
|
|
112
|
+
themeObserver.observe(document.documentElement, {
|
|
113
|
+
attributes: true,
|
|
114
|
+
attributeFilter: ['data-theme', 'class', 'style']
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Also watch body for theme class changes
|
|
118
|
+
if (document.body) {
|
|
119
|
+
themeObserver.observe(document.body, {
|
|
120
|
+
attributes: true,
|
|
121
|
+
attributeFilter: ['class', 'data-theme']
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
onBeforeUnmount(() => {
|
|
128
|
+
themeObserver?.disconnect()
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// Global testing functions
|
|
132
|
+
if ('undefined' !== typeof window) {
|
|
133
|
+
(window as any).testRichTextTheme = () => {
|
|
134
|
+
console.log('🧪 Testing RichText theme:', {
|
|
135
|
+
currentInputColor: currentInputColor.value,
|
|
136
|
+
currentTextColor: currentTextColor.value,
|
|
137
|
+
hasInitialized: hasInitialized.value,
|
|
138
|
+
hasIframe: !!iframe.value,
|
|
139
|
+
cssVar: getComputedStyle(document.documentElement).getPropertyValue('--input-color')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
if (hasInitialized.value) {
|
|
143
|
+
updateIframeColors()
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
(window as any).forceRichTextUpdate = () => {
|
|
148
|
+
console.log('🔄 Forcing RichText update')
|
|
149
|
+
forceUpdate.value++
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
55
153
|
// Computed properties for UI control
|
|
56
154
|
const shouldShowToolbar = computed(() => {
|
|
57
|
-
if (props.hideToolbar) return false
|
|
58
|
-
if (props.basic) return false
|
|
155
|
+
if (props.hideToolbar) {return false}
|
|
156
|
+
if (props.basic) {return false}
|
|
59
157
|
return true
|
|
60
158
|
})
|
|
61
159
|
|
|
62
160
|
const shouldShowInlineToolbar = computed(() => {
|
|
63
|
-
if (props.hideInlineToolbar) return false
|
|
161
|
+
if (props.hideInlineToolbar) {return false}
|
|
64
162
|
return true
|
|
65
163
|
})
|
|
66
164
|
|
|
@@ -239,7 +337,7 @@ const tablePreviewHtml = computed(() => {
|
|
|
239
337
|
border: ${form.borderWidth}px solid ${form.borderColor};
|
|
240
338
|
text-align: ${form.alignment};
|
|
241
339
|
${form.fixedLayout ? `width: ${100 / form.cols}%;` : ''}
|
|
242
|
-
${form.alternateRows && i % 2
|
|
340
|
+
${form.alternateRows && 1 === i % 2
|
|
243
341
|
? `background-color: ${form.alternateRowBgColor}; color: ${form.alternateRowTextColor};`
|
|
244
342
|
: `background-color: ${form.cellBgColor}; color: ${form.cellTextColor};`}
|
|
245
343
|
`
|
|
@@ -301,7 +399,7 @@ function detectAndSetDirection() {
|
|
|
301
399
|
// Function to get current direction based on content
|
|
302
400
|
function getCurrentDirection() {
|
|
303
401
|
const { doc } = editor.state
|
|
304
|
-
if (!doc?.body) return 'ltr'
|
|
402
|
+
if (!doc?.body) {return 'ltr'}
|
|
305
403
|
|
|
306
404
|
const allText = doc.body.textContent || ''
|
|
307
405
|
const firstChars = allText.trim().substring(0, 10)
|
|
@@ -312,7 +410,7 @@ function getCurrentDirection() {
|
|
|
312
410
|
|
|
313
411
|
// Helper function to update content with history tracking
|
|
314
412
|
function updateContentWithHistory(doc: Document, skipHistory = false) {
|
|
315
|
-
if (!doc) return
|
|
413
|
+
if (!doc) {return}
|
|
316
414
|
|
|
317
415
|
const newContent = doc.body.innerHTML
|
|
318
416
|
if (newContent !== editor.state.content) {
|
|
@@ -322,7 +420,7 @@ function updateContentWithHistory(doc: Document, skipHistory = false) {
|
|
|
322
420
|
// Clear redo stack when new content is added
|
|
323
421
|
editor.state.redoStack = []
|
|
324
422
|
// Limit undo stack size to prevent memory issues
|
|
325
|
-
if (editor.state.undoStack.length
|
|
423
|
+
if (50 < editor.state.undoStack.length) {
|
|
326
424
|
editor.state.undoStack.shift()
|
|
327
425
|
}
|
|
328
426
|
}
|
|
@@ -374,10 +472,10 @@ function showInlineToolbarForSelection() {
|
|
|
374
472
|
}
|
|
375
473
|
|
|
376
474
|
const { doc } = editor.state
|
|
377
|
-
if (!doc) return
|
|
475
|
+
if (!doc) {return}
|
|
378
476
|
|
|
379
477
|
const selection = doc.getSelection()
|
|
380
|
-
if (!selection || selection.rangeCount
|
|
478
|
+
if (!selection || 0 === selection.rangeCount) {
|
|
381
479
|
hideInlineToolbar()
|
|
382
480
|
return
|
|
383
481
|
}
|
|
@@ -431,14 +529,14 @@ function hideInlineToolbar() {
|
|
|
431
529
|
|
|
432
530
|
// Function to run inline toolbar action
|
|
433
531
|
function runInlineAction(actionName: string) {
|
|
434
|
-
if (!inlineToolbarSelection.value) return
|
|
532
|
+
if (!inlineToolbarSelection.value) {return}
|
|
435
533
|
|
|
436
534
|
const { doc } = editor.state
|
|
437
|
-
if (!doc) return
|
|
535
|
+
if (!doc) {return}
|
|
438
536
|
|
|
439
537
|
// Get the stored range
|
|
440
538
|
const storedRange = (inlineToolbarSelection.value as any)._storedRange as Range
|
|
441
|
-
if (!storedRange) return
|
|
539
|
+
if (!storedRange) {return}
|
|
442
540
|
|
|
443
541
|
// Restore selection using the stored range
|
|
444
542
|
const selection = doc.getSelection()
|
|
@@ -453,7 +551,7 @@ function runInlineAction(actionName: string) {
|
|
|
453
551
|
// Keep the toolbar visible but update the stored selection
|
|
454
552
|
setTimeout(() => {
|
|
455
553
|
const newSelection = doc.getSelection()
|
|
456
|
-
if (newSelection && newSelection.rangeCount
|
|
554
|
+
if (newSelection && 0 < newSelection.rangeCount) {
|
|
457
555
|
const newRange = newSelection.getRangeAt(0)
|
|
458
556
|
if (!newRange.collapsed) {
|
|
459
557
|
; (inlineToolbarSelection.value as any)._storedRange = newRange.cloneRange()
|
|
@@ -474,7 +572,7 @@ function showTooltipMessage(message: string, x?: number, y?: number) {
|
|
|
474
572
|
// If coordinates not provided, try to get cursor position
|
|
475
573
|
if (x === undefined || y === undefined) {
|
|
476
574
|
const selection = editor.state.doc?.getSelection()
|
|
477
|
-
if (selection && selection.rangeCount
|
|
575
|
+
if (selection && 0 < selection.rangeCount) {
|
|
478
576
|
const range = selection.getRangeAt(0)
|
|
479
577
|
const rect = range.getBoundingClientRect()
|
|
480
578
|
// Get iframe offset
|
|
@@ -510,20 +608,20 @@ function openLinkModal(selection: Selection, range: Range, existingLink: HTMLAnc
|
|
|
510
608
|
pendingLinkData = { selection, range, existingLink }
|
|
511
609
|
linkForm.value = {
|
|
512
610
|
url: existingLink?.href || '',
|
|
513
|
-
openInNewTab: existingLink?.target
|
|
611
|
+
openInNewTab: '_self' !== existingLink?.target
|
|
514
612
|
}
|
|
515
613
|
showLinkModal.value = true
|
|
516
614
|
}
|
|
517
615
|
|
|
518
616
|
// Function to submit link
|
|
519
617
|
function submitLink() {
|
|
520
|
-
if (!pendingLinkData || !linkForm.value.url) return
|
|
618
|
+
if (!pendingLinkData || !linkForm.value.url) {return}
|
|
521
619
|
|
|
522
620
|
const { selection, range, existingLink } = pendingLinkData
|
|
523
621
|
const { url, openInNewTab } = linkForm.value
|
|
524
622
|
const { doc } = editor.state
|
|
525
623
|
|
|
526
|
-
if (!doc) return
|
|
624
|
+
if (!doc) {return}
|
|
527
625
|
|
|
528
626
|
if (existingLink) {
|
|
529
627
|
// Update existing link
|
|
@@ -570,7 +668,7 @@ function submitLink() {
|
|
|
570
668
|
|
|
571
669
|
// Function to visit link
|
|
572
670
|
function visitLink() {
|
|
573
|
-
if (!linkForm.value.url || !isValidUrl(linkForm.value.url)) return
|
|
671
|
+
if (!linkForm.value.url || !isValidUrl(linkForm.value.url)) {return}
|
|
574
672
|
|
|
575
673
|
let url = linkForm.value.url.trim()
|
|
576
674
|
|
|
@@ -588,7 +686,7 @@ function visitLink() {
|
|
|
588
686
|
|
|
589
687
|
// Function to validate URL
|
|
590
688
|
function isValidUrl(url: string): boolean {
|
|
591
|
-
if (!url || url.trim()
|
|
689
|
+
if (!url || '' === url.trim()) {return false}
|
|
592
690
|
|
|
593
691
|
try {
|
|
594
692
|
URL.canParse(url)
|
|
@@ -607,12 +705,12 @@ function isValidUrl(url: string): boolean {
|
|
|
607
705
|
// Function to open image modal
|
|
608
706
|
function openImageModal(existingImage: HTMLElement | null = null) {
|
|
609
707
|
const { doc } = editor.state
|
|
610
|
-
if (!doc) return
|
|
708
|
+
if (!doc) {return}
|
|
611
709
|
|
|
612
710
|
// Get current selection for new images
|
|
613
711
|
if (!existingImage) {
|
|
614
712
|
const selection = doc.getSelection()
|
|
615
|
-
if (!selection || !selection.rangeCount) return
|
|
713
|
+
if (!selection || !selection.rangeCount) {return}
|
|
616
714
|
const range = selection.getRangeAt(0)
|
|
617
715
|
pendingImageData = { selection, range, existingImage: null }
|
|
618
716
|
} else {
|
|
@@ -656,10 +754,10 @@ function openImageModal(existingImage: HTMLElement | null = null) {
|
|
|
656
754
|
|
|
657
755
|
// Function to submit image
|
|
658
756
|
function submitImage() {
|
|
659
|
-
if (!imageForm.value.src || !pendingImageData) return
|
|
757
|
+
if (!imageForm.value.src || !pendingImageData) {return}
|
|
660
758
|
|
|
661
759
|
const { doc } = editor.state
|
|
662
|
-
if (!doc) return
|
|
760
|
+
if (!doc) {return}
|
|
663
761
|
|
|
664
762
|
const { existingImage } = pendingImageData
|
|
665
763
|
|
|
@@ -682,7 +780,7 @@ function submitImage() {
|
|
|
682
780
|
|
|
683
781
|
if (imageForm.value.height) {
|
|
684
782
|
img.setAttribute('data-height', imageForm.value.height)
|
|
685
|
-
if (imageForm.value.height.includes('%') || imageForm.value.height.includes('px') || imageForm.value.height.includes('vh') || imageForm.value.height.includes('rem') || imageForm.value.height.includes('em') || imageForm.value.height
|
|
783
|
+
if (imageForm.value.height.includes('%') || imageForm.value.height.includes('px') || imageForm.value.height.includes('vh') || imageForm.value.height.includes('rem') || imageForm.value.height.includes('em') || 'auto' === imageForm.value.height) {
|
|
686
784
|
img.style.height = imageForm.value.height
|
|
687
785
|
} else {
|
|
688
786
|
img.style.height = `${imageForm.value.height}px`
|
|
@@ -713,7 +811,7 @@ function submitImage() {
|
|
|
713
811
|
// Create or update figure/image - always wrap in figure
|
|
714
812
|
let elementToUpdate: HTMLElement
|
|
715
813
|
if (existingImage) {
|
|
716
|
-
if (existingImage.tagName.toLowerCase()
|
|
814
|
+
if ('img' === existingImage.tagName.toLowerCase()) {
|
|
717
815
|
// Converting standalone image to figure (always)
|
|
718
816
|
const figure = doc.createElement('figure')
|
|
719
817
|
figure.className = 'image-figure'
|
|
@@ -778,12 +876,12 @@ function submitImage() {
|
|
|
778
876
|
// Function to open embed modal
|
|
779
877
|
function openEmbedModal(existingEmbed: HTMLElement | null = null) {
|
|
780
878
|
const { doc } = editor.state
|
|
781
|
-
if (!doc) return
|
|
879
|
+
if (!doc) {return}
|
|
782
880
|
|
|
783
881
|
// Get current selection for new embeds
|
|
784
882
|
if (!existingEmbed) {
|
|
785
883
|
const selection = doc.getSelection()
|
|
786
|
-
if (!selection || !selection.rangeCount) return
|
|
884
|
+
if (!selection || !selection.rangeCount) {return}
|
|
787
885
|
const range = selection.getRangeAt(0)
|
|
788
886
|
pendingEmbedData = { selection, range, existingEmbed: null }
|
|
789
887
|
} else {
|
|
@@ -837,10 +935,10 @@ function extractEmbedUrl(input: string): string {
|
|
|
837
935
|
|
|
838
936
|
// Function to submit embed
|
|
839
937
|
function submitEmbed() {
|
|
840
|
-
if (!embedForm.value.src || !pendingEmbedData) return
|
|
938
|
+
if (!embedForm.value.src || !pendingEmbedData) {return}
|
|
841
939
|
|
|
842
940
|
const { doc } = editor.state
|
|
843
|
-
if (!doc) return
|
|
941
|
+
if (!doc) {return}
|
|
844
942
|
|
|
845
943
|
const { existingEmbed } = pendingEmbedData
|
|
846
944
|
|
|
@@ -917,12 +1015,12 @@ function submitEmbed() {
|
|
|
917
1015
|
// Function to open video modal
|
|
918
1016
|
function openVideoModal(existingVideo: HTMLElement | null = null) {
|
|
919
1017
|
const { doc } = editor.state
|
|
920
|
-
if (!doc) return
|
|
1018
|
+
if (!doc) {return}
|
|
921
1019
|
|
|
922
1020
|
// Get current selection for new videos
|
|
923
1021
|
if (!existingVideo) {
|
|
924
1022
|
const selection = doc.getSelection()
|
|
925
|
-
if (!selection || !selection.rangeCount) return
|
|
1023
|
+
if (!selection || !selection.rangeCount) {return}
|
|
926
1024
|
const range = selection.getRangeAt(0)
|
|
927
1025
|
pendingVideoData = { selection, range, existingVideo: null }
|
|
928
1026
|
} else {
|
|
@@ -937,14 +1035,14 @@ function openVideoModal(existingVideo: HTMLElement | null = null) {
|
|
|
937
1035
|
if (existingVideo) {
|
|
938
1036
|
// Populate form with existing video data
|
|
939
1037
|
const container = existingVideo.querySelector('.video-container')
|
|
940
|
-
const isCustom = container?.getAttribute('data-custom-aspect-ratio')
|
|
1038
|
+
const isCustom = 'true' === container?.getAttribute('data-custom-aspect-ratio')
|
|
941
1039
|
videoForm.value = {
|
|
942
1040
|
src: container?.getAttribute('data-video-src') || '',
|
|
943
1041
|
width: container?.getAttribute('data-width') || '',
|
|
944
|
-
autoplay: container?.getAttribute('data-autoplay')
|
|
945
|
-
mute: container?.getAttribute('data-mute')
|
|
946
|
-
controls: container?.getAttribute('data-controls')
|
|
947
|
-
loop: container?.getAttribute('data-loop')
|
|
1042
|
+
autoplay: 'true' === container?.getAttribute('data-autoplay'),
|
|
1043
|
+
mute: 'true' === container?.getAttribute('data-mute'),
|
|
1044
|
+
controls: 'true' === container?.getAttribute('data-controls'),
|
|
1045
|
+
loop: 'true' === container?.getAttribute('data-loop'),
|
|
948
1046
|
aspectRatio: isCustom ? 'custom' : (container?.getAttribute('data-aspect-ratio') || '16:9'),
|
|
949
1047
|
customWidth: container?.getAttribute('data-custom-width') || '',
|
|
950
1048
|
customHeight: container?.getAttribute('data-custom-height') || '',
|
|
@@ -973,7 +1071,7 @@ function openVideoModal(existingVideo: HTMLElement | null = null) {
|
|
|
973
1071
|
|
|
974
1072
|
// Function to validate video URL
|
|
975
1073
|
function isValidVideoUrl(url: string): boolean {
|
|
976
|
-
if (!url || url.trim()
|
|
1074
|
+
if (!url || '' === url.trim()) {return false}
|
|
977
1075
|
|
|
978
1076
|
try {
|
|
979
1077
|
// Check for iframe tags
|
|
@@ -1008,23 +1106,23 @@ function isValidVideoUrl(url: string): boolean {
|
|
|
1008
1106
|
}
|
|
1009
1107
|
}
|
|
1010
1108
|
function submitVideo() {
|
|
1011
|
-
if (!videoForm.value.src || !pendingVideoData) return
|
|
1109
|
+
if (!videoForm.value.src || !pendingVideoData) {return}
|
|
1012
1110
|
|
|
1013
1111
|
const { doc } = editor.state
|
|
1014
|
-
if (!doc) return
|
|
1112
|
+
if (!doc) {return}
|
|
1015
1113
|
|
|
1016
1114
|
const { existingVideo } = pendingVideoData
|
|
1017
1115
|
|
|
1018
1116
|
// Calculate aspect ratio
|
|
1019
1117
|
let { aspectRatio } = videoForm.value
|
|
1020
|
-
const isCustom = videoForm.value.aspectRatio
|
|
1118
|
+
const isCustom = 'custom' === videoForm.value.aspectRatio
|
|
1021
1119
|
if (isCustom && videoForm.value.customWidth && videoForm.value.customHeight) {
|
|
1022
1120
|
aspectRatio = `${videoForm.value.customWidth}:${videoForm.value.customHeight}`
|
|
1023
1121
|
}
|
|
1024
1122
|
|
|
1025
1123
|
// Auto-adjust aspect ratio for YouTube Shorts
|
|
1026
1124
|
const isYoutubeShort = videoForm.value.src.includes('youtube.com/shorts/')
|
|
1027
|
-
if (isYoutubeShort &&
|
|
1125
|
+
if (isYoutubeShort && '16:9' === aspectRatio) {
|
|
1028
1126
|
aspectRatio = '9:16'
|
|
1029
1127
|
}
|
|
1030
1128
|
|
|
@@ -1072,8 +1170,8 @@ function submitVideo() {
|
|
|
1072
1170
|
const description = doc.createElement('div')
|
|
1073
1171
|
description.className = 'video-placeholder-description'
|
|
1074
1172
|
let platformText = 'video'
|
|
1075
|
-
if (isYoutube) platformText = 'YouTube video'
|
|
1076
|
-
else if (isVimeo) platformText = 'Vimeo video'
|
|
1173
|
+
if (isYoutube) {platformText = 'YouTube video'}
|
|
1174
|
+
else if (isVimeo) {platformText = 'Vimeo video'}
|
|
1077
1175
|
description.textContent = platformText
|
|
1078
1176
|
|
|
1079
1177
|
// Try to get YouTube thumbnail if possible
|
|
@@ -1162,7 +1260,7 @@ function submitVideo() {
|
|
|
1162
1260
|
|
|
1163
1261
|
// Function to delete video
|
|
1164
1262
|
function deleteVideo() {
|
|
1165
|
-
if (!pendingVideoData?.existingVideo) return
|
|
1263
|
+
if (!pendingVideoData?.existingVideo) {return}
|
|
1166
1264
|
|
|
1167
1265
|
const { existingVideo } = pendingVideoData
|
|
1168
1266
|
existingVideo.remove()
|
|
@@ -1181,9 +1279,9 @@ function detectTableAlignment(table: HTMLTableElement): 'left' | 'center' | 'rig
|
|
|
1181
1279
|
|
|
1182
1280
|
console.log('Table margins:', { marginLeft, marginRight })
|
|
1183
1281
|
|
|
1184
|
-
if (
|
|
1282
|
+
if ('auto' === marginLeft && 'auto' === marginRight) {
|
|
1185
1283
|
return 'center'
|
|
1186
|
-
}
|
|
1284
|
+
}if (marginLeft === 'auto' && marginRight === '0') {
|
|
1187
1285
|
return 'right'
|
|
1188
1286
|
} else {
|
|
1189
1287
|
return 'left'
|
|
@@ -1192,12 +1290,12 @@ function detectTableAlignment(table: HTMLTableElement): 'left' | 'center' | 'rig
|
|
|
1192
1290
|
|
|
1193
1291
|
function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
1194
1292
|
const { doc } = editor.state
|
|
1195
|
-
if (!doc) return
|
|
1293
|
+
if (!doc) {return}
|
|
1196
1294
|
|
|
1197
1295
|
// Get current selection for new tables
|
|
1198
1296
|
if (!existingTable) {
|
|
1199
1297
|
const selection = doc.getSelection()
|
|
1200
|
-
if (!selection || !selection.rangeCount) return
|
|
1298
|
+
if (!selection || !selection.rangeCount) {return}
|
|
1201
1299
|
const range = selection.getRangeAt(0)
|
|
1202
1300
|
pendingTableData = { selection, range, existingTable: null }
|
|
1203
1301
|
} else {
|
|
@@ -1219,11 +1317,11 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1219
1317
|
let alternateRowBg = '#f9f9f9'
|
|
1220
1318
|
let alternateRowTextColor = '#333333'
|
|
1221
1319
|
|
|
1222
|
-
if (tbody && tbody.rows.length
|
|
1320
|
+
if (tbody && 2 <= tbody.rows.length) {
|
|
1223
1321
|
const firstRow = tbody.rows[0]
|
|
1224
1322
|
const secondRow = tbody.rows[1]
|
|
1225
1323
|
|
|
1226
|
-
if (firstRow.cells.length
|
|
1324
|
+
if (0 < firstRow.cells.length && 0 < secondRow.cells.length) {
|
|
1227
1325
|
const firstCell = firstRow.cells[0] as HTMLElement
|
|
1228
1326
|
const secondCell = secondRow.cells[0] as HTMLElement
|
|
1229
1327
|
|
|
@@ -1241,7 +1339,7 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1241
1339
|
|
|
1242
1340
|
tableForm.value = {
|
|
1243
1341
|
rows: tbody ? tbody.rows.length : 3,
|
|
1244
|
-
cols: tbody && tbody.rows.length
|
|
1342
|
+
cols: tbody && 0 < tbody.rows.length ? tbody.rows[0].cells.length : 3,
|
|
1245
1343
|
width: Number.parseInt(existingTable.style.width) || 100,
|
|
1246
1344
|
borderWidth: Number.parseInt(existingTable.style.borderWidth) || 1,
|
|
1247
1345
|
borderColor: existingTable.style.borderColor || '#dddddd',
|
|
@@ -1254,7 +1352,7 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1254
1352
|
alternateRows: hasAlternatingRows,
|
|
1255
1353
|
alternateRowBgColor: alternateRowBg,
|
|
1256
1354
|
alternateRowTextColor,
|
|
1257
|
-
fixedLayout: existingTable.style.tableLayout
|
|
1355
|
+
fixedLayout: 'fixed' === existingTable.style.tableLayout || true, // ברירת מחדל true
|
|
1258
1356
|
alignment: detectTableAlignment(existingTable),
|
|
1259
1357
|
direction: existingTable.dir || 'ltr'
|
|
1260
1358
|
}
|
|
@@ -1284,10 +1382,10 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1284
1382
|
|
|
1285
1383
|
// Function to submit table changes
|
|
1286
1384
|
function submitTable() {
|
|
1287
|
-
if (!pendingTableData) return
|
|
1385
|
+
if (!pendingTableData) {return}
|
|
1288
1386
|
|
|
1289
1387
|
const { doc } = editor.state
|
|
1290
|
-
if (!doc) return
|
|
1388
|
+
if (!doc) {return}
|
|
1291
1389
|
|
|
1292
1390
|
if (pendingTableData.existingTable) {
|
|
1293
1391
|
// Update existing table instead of creating new one
|
|
@@ -1347,7 +1445,7 @@ function submitTable() {
|
|
|
1347
1445
|
const cells = row.querySelectorAll('td')
|
|
1348
1446
|
cells.forEach((cell) => {
|
|
1349
1447
|
const cellEl = cell as HTMLElement
|
|
1350
|
-
if (tableForm.value.alternateRows && i % 2
|
|
1448
|
+
if (tableForm.value.alternateRows && 1 === i % 2) {
|
|
1351
1449
|
// Alternate rows: use special colors
|
|
1352
1450
|
cellEl.style.backgroundColor = tableForm.value.alternateRowBgColor
|
|
1353
1451
|
cellEl.style.color = tableForm.value.alternateRowTextColor
|
|
@@ -1372,7 +1470,7 @@ function submitTable() {
|
|
|
1372
1470
|
|
|
1373
1471
|
// Function to create new table (moved from submitTable)
|
|
1374
1472
|
function createNewTable(doc: Document) {
|
|
1375
|
-
if (!pendingTableData) return
|
|
1473
|
+
if (!pendingTableData) {return}
|
|
1376
1474
|
|
|
1377
1475
|
// Create new table with current settings
|
|
1378
1476
|
const table = doc.createElement('table')
|
|
@@ -1392,10 +1490,10 @@ function createNewTable(doc: Document) {
|
|
|
1392
1490
|
// Don't set textAlign on table - let it inherit from document direction
|
|
1393
1491
|
// table.style.textAlign = tableForm.value.alignment
|
|
1394
1492
|
|
|
1395
|
-
if (tableForm.value.alignment
|
|
1493
|
+
if ('center' === tableForm.value.alignment) {
|
|
1396
1494
|
table.style.marginLeft = 'auto'
|
|
1397
1495
|
table.style.marginRight = 'auto'
|
|
1398
|
-
} else if (tableForm.value.alignment
|
|
1496
|
+
} else if ('right' === tableForm.value.alignment) {
|
|
1399
1497
|
table.style.marginLeft = 'auto'
|
|
1400
1498
|
table.style.marginRight = '0'
|
|
1401
1499
|
} else {
|
|
@@ -1448,7 +1546,7 @@ function createNewTable(doc: Document) {
|
|
|
1448
1546
|
}
|
|
1449
1547
|
|
|
1450
1548
|
// Apply background and text colors
|
|
1451
|
-
if (tableForm.value.alternateRows && i % 2
|
|
1549
|
+
if (tableForm.value.alternateRows && 1 === i % 2) {
|
|
1452
1550
|
// Alternate rows: use special colors
|
|
1453
1551
|
cell.style.backgroundColor = tableForm.value.alternateRowBgColor
|
|
1454
1552
|
cell.style.color = tableForm.value.alternateRowTextColor
|
|
@@ -1492,7 +1590,7 @@ function createNewTable(doc: Document) {
|
|
|
1492
1590
|
|
|
1493
1591
|
// Function to delete table
|
|
1494
1592
|
function deleteTable() {
|
|
1495
|
-
if (!pendingTableData?.existingTable) return
|
|
1593
|
+
if (!pendingTableData?.existingTable) {return}
|
|
1496
1594
|
|
|
1497
1595
|
const { existingTable } = pendingTableData
|
|
1498
1596
|
existingTable.remove()
|
|
@@ -1521,7 +1619,7 @@ function applyDefaultTableSettings(table: HTMLTableElement) {
|
|
|
1521
1619
|
const headers = table.querySelectorAll('th')
|
|
1522
1620
|
const cells = table.querySelectorAll('td')
|
|
1523
1621
|
|
|
1524
|
-
if (headers.length
|
|
1622
|
+
if (0 < headers.length) {
|
|
1525
1623
|
const colWidth = `${100 / headers.length}%`
|
|
1526
1624
|
headers.forEach((th) => {
|
|
1527
1625
|
if (!(th as HTMLElement).style.width) {
|
|
@@ -1530,7 +1628,7 @@ function applyDefaultTableSettings(table: HTMLTableElement) {
|
|
|
1530
1628
|
})
|
|
1531
1629
|
}
|
|
1532
1630
|
|
|
1533
|
-
if (cells.length
|
|
1631
|
+
if (0 < cells.length && 0 === headers.length) {
|
|
1534
1632
|
// If no headers, use first row to determine column count
|
|
1535
1633
|
const firstRow = table.querySelector('tr')
|
|
1536
1634
|
if (firstRow) {
|
|
@@ -1560,7 +1658,7 @@ function applyDefaultTableSettings(table: HTMLTableElement) {
|
|
|
1560
1658
|
|
|
1561
1659
|
// Function to delete image
|
|
1562
1660
|
function deleteImage() {
|
|
1563
|
-
if (!pendingImageData?.existingImage) return
|
|
1661
|
+
if (!pendingImageData?.existingImage) {return}
|
|
1564
1662
|
|
|
1565
1663
|
const { existingImage } = pendingImageData
|
|
1566
1664
|
existingImage.remove()
|
|
@@ -1572,7 +1670,7 @@ function deleteImage() {
|
|
|
1572
1670
|
|
|
1573
1671
|
// Function to delete embed
|
|
1574
1672
|
function deleteEmbed() {
|
|
1575
|
-
if (!pendingEmbedData?.existingEmbed) return
|
|
1673
|
+
if (!pendingEmbedData?.existingEmbed) {return}
|
|
1576
1674
|
|
|
1577
1675
|
const { existingEmbed } = pendingEmbedData
|
|
1578
1676
|
existingEmbed.remove()
|
|
@@ -1595,19 +1693,19 @@ function deleteEmbed() {
|
|
|
1595
1693
|
// Table manipulation functions
|
|
1596
1694
|
function mergeCellRight() {
|
|
1597
1695
|
const { doc } = editor.state
|
|
1598
|
-
if (!doc || !contextMenuCell.value) return
|
|
1696
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1599
1697
|
|
|
1600
1698
|
const cell = contextMenuCell.value
|
|
1601
1699
|
const row = cell.parentElement as HTMLTableRowElement
|
|
1602
1700
|
const cellIndex = Array.from(row.cells).indexOf(cell)
|
|
1603
1701
|
const table = cell.closest('table') as HTMLTableElement
|
|
1604
|
-
const isRTL = table?.dir
|
|
1702
|
+
const isRTL = 'rtl' === table?.dir
|
|
1605
1703
|
|
|
1606
1704
|
// In RTL, "right" means the previous cell, in LTR it means the next cell
|
|
1607
1705
|
const targetIndex = isRTL ? cellIndex - 1 : cellIndex + 1
|
|
1608
1706
|
const targetCell = row.cells[targetIndex]
|
|
1609
1707
|
|
|
1610
|
-
if (targetCell &&
|
|
1708
|
+
if (targetCell && 0 <= targetIndex && targetIndex < row.cells.length) {
|
|
1611
1709
|
// Combine content
|
|
1612
1710
|
if (targetCell.innerHTML.trim()) {
|
|
1613
1711
|
cell.innerHTML += ` ${targetCell.innerHTML}`
|
|
@@ -1627,7 +1725,7 @@ function mergeCellRight() {
|
|
|
1627
1725
|
|
|
1628
1726
|
function mergeCellDown() {
|
|
1629
1727
|
const { doc } = editor.state
|
|
1630
|
-
if (!doc || !contextMenuCell.value) return
|
|
1728
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1631
1729
|
|
|
1632
1730
|
const cell = contextMenuCell.value
|
|
1633
1731
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1663,15 +1761,15 @@ function mergeCellDown() {
|
|
|
1663
1761
|
|
|
1664
1762
|
function splitCell() {
|
|
1665
1763
|
const { doc } = editor.state
|
|
1666
|
-
if (!doc || !contextMenuCell.value) return
|
|
1764
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1667
1765
|
|
|
1668
1766
|
const cell = contextMenuCell.value
|
|
1669
1767
|
const table = cell.closest('table') as HTMLTableElement
|
|
1670
|
-
const isRTL = table?.dir
|
|
1768
|
+
const isRTL = 'rtl' === table?.dir
|
|
1671
1769
|
const colspan = Number.parseInt(cell.getAttribute('colspan') || '1')
|
|
1672
1770
|
const rowspan = Number.parseInt(cell.getAttribute('rowspan') || '1')
|
|
1673
1771
|
|
|
1674
|
-
if (
|
|
1772
|
+
if (1 < colspan) {
|
|
1675
1773
|
// Split horizontally
|
|
1676
1774
|
cell.setAttribute('colspan', '1')
|
|
1677
1775
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1692,7 +1790,7 @@ function splitCell() {
|
|
|
1692
1790
|
}
|
|
1693
1791
|
}
|
|
1694
1792
|
}
|
|
1695
|
-
} else if (
|
|
1793
|
+
} else if (1 < rowspan) {
|
|
1696
1794
|
// Split vertically
|
|
1697
1795
|
cell.setAttribute('rowspan', '1')
|
|
1698
1796
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1724,7 +1822,7 @@ function splitCell() {
|
|
|
1724
1822
|
|
|
1725
1823
|
function insertRowAbove() {
|
|
1726
1824
|
const { doc } = editor.state
|
|
1727
|
-
if (!doc || !contextMenuCell.value) return
|
|
1825
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1728
1826
|
|
|
1729
1827
|
const cell = contextMenuCell.value
|
|
1730
1828
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1751,7 +1849,7 @@ function insertRowAbove() {
|
|
|
1751
1849
|
|
|
1752
1850
|
function insertRowBelow() {
|
|
1753
1851
|
const { doc } = editor.state
|
|
1754
|
-
if (!doc || !contextMenuCell.value) return
|
|
1852
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1755
1853
|
|
|
1756
1854
|
const cell = contextMenuCell.value
|
|
1757
1855
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1778,7 +1876,7 @@ function insertRowBelow() {
|
|
|
1778
1876
|
|
|
1779
1877
|
function deleteRow() {
|
|
1780
1878
|
const { doc } = editor.state
|
|
1781
|
-
if (!doc || !contextMenuCell.value) return
|
|
1879
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1782
1880
|
|
|
1783
1881
|
const cell = contextMenuCell.value
|
|
1784
1882
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1788,7 +1886,7 @@ function deleteRow() {
|
|
|
1788
1886
|
const tbody = table.querySelector('tbody') || table
|
|
1789
1887
|
const rows = tbody.querySelectorAll('tr')
|
|
1790
1888
|
|
|
1791
|
-
if (rows.length
|
|
1889
|
+
if (1 >= rows.length) {
|
|
1792
1890
|
alert('Cannot delete the last row')
|
|
1793
1891
|
return
|
|
1794
1892
|
}
|
|
@@ -1799,7 +1897,7 @@ function deleteRow() {
|
|
|
1799
1897
|
|
|
1800
1898
|
function insertColumnLeft() {
|
|
1801
1899
|
const { doc } = editor.state
|
|
1802
|
-
if (!doc || !contextMenuCell.value) return
|
|
1900
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1803
1901
|
|
|
1804
1902
|
const cell = contextMenuCell.value
|
|
1805
1903
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1808,7 +1906,7 @@ function insertColumnLeft() {
|
|
|
1808
1906
|
// Add new cell to each row at the same index
|
|
1809
1907
|
const rows = table.querySelectorAll('tr')
|
|
1810
1908
|
rows.forEach((row) => {
|
|
1811
|
-
const newCell = doc.createElement(row.parentElement?.tagName
|
|
1909
|
+
const newCell = doc.createElement('THEAD' === row.parentElement?.tagName ? 'th' : 'td')
|
|
1812
1910
|
newCell.innerHTML = ' '
|
|
1813
1911
|
newCell.style.padding = '8px'
|
|
1814
1912
|
newCell.style.border = '1px solid #ddd'
|
|
@@ -1825,7 +1923,7 @@ function insertColumnLeft() {
|
|
|
1825
1923
|
|
|
1826
1924
|
function insertColumnRight() {
|
|
1827
1925
|
const { doc } = editor.state
|
|
1828
|
-
if (!doc || !contextMenuCell.value) return
|
|
1926
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1829
1927
|
|
|
1830
1928
|
const cell = contextMenuCell.value
|
|
1831
1929
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1834,7 +1932,7 @@ function insertColumnRight() {
|
|
|
1834
1932
|
// Add new cell to each row after the current index
|
|
1835
1933
|
const rows = table.querySelectorAll('tr')
|
|
1836
1934
|
rows.forEach((row) => {
|
|
1837
|
-
const newCell = doc.createElement(row.parentElement?.tagName
|
|
1935
|
+
const newCell = doc.createElement('THEAD' === row.parentElement?.tagName ? 'th' : 'td')
|
|
1838
1936
|
newCell.innerHTML = ' '
|
|
1839
1937
|
newCell.style.padding = '8px'
|
|
1840
1938
|
newCell.style.border = '1px solid #ddd'
|
|
@@ -1852,7 +1950,7 @@ function insertColumnRight() {
|
|
|
1852
1950
|
|
|
1853
1951
|
function deleteColumn() {
|
|
1854
1952
|
const { doc } = editor.state
|
|
1855
|
-
if (!doc || !contextMenuCell.value) return
|
|
1953
|
+
if (!doc || !contextMenuCell.value) {return}
|
|
1856
1954
|
|
|
1857
1955
|
const cell = contextMenuCell.value
|
|
1858
1956
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1860,7 +1958,7 @@ function deleteColumn() {
|
|
|
1860
1958
|
|
|
1861
1959
|
// Check if this is the only column
|
|
1862
1960
|
const firstRow = table.querySelector('tr')
|
|
1863
|
-
if (firstRow && firstRow.cells.length
|
|
1961
|
+
if (firstRow && 1 >= firstRow.cells.length) {
|
|
1864
1962
|
alert('Cannot delete the last column')
|
|
1865
1963
|
return
|
|
1866
1964
|
}
|
|
@@ -1878,18 +1976,18 @@ function deleteColumn() {
|
|
|
1878
1976
|
|
|
1879
1977
|
// Table context menu functions
|
|
1880
1978
|
const canMergeRight = computed(() => {
|
|
1881
|
-
if (!contextMenuCell.value) return false
|
|
1979
|
+
if (!contextMenuCell.value) {return false}
|
|
1882
1980
|
const cell = contextMenuCell.value
|
|
1883
1981
|
const row = cell.parentElement as HTMLTableRowElement
|
|
1884
1982
|
const cellIndex = Array.from(row.cells).indexOf(cell)
|
|
1885
1983
|
const table = cell.closest('table') as HTMLTableElement
|
|
1886
|
-
const isRTL = table?.dir
|
|
1984
|
+
const isRTL = 'rtl' === table?.dir
|
|
1887
1985
|
const targetIndex = isRTL ? cellIndex - 1 : cellIndex + 1
|
|
1888
|
-
return
|
|
1986
|
+
return 0 <= targetIndex && targetIndex < row.cells.length
|
|
1889
1987
|
})
|
|
1890
1988
|
|
|
1891
1989
|
const canMergeDown = computed(() => {
|
|
1892
|
-
if (!contextMenuCell.value) return false
|
|
1990
|
+
if (!contextMenuCell.value) {return false}
|
|
1893
1991
|
const cell = contextMenuCell.value
|
|
1894
1992
|
const table = cell.closest('table') as HTMLTableElement
|
|
1895
1993
|
const rows = Array.from(table.rows)
|
|
@@ -1899,11 +1997,11 @@ const canMergeDown = computed(() => {
|
|
|
1899
1997
|
})
|
|
1900
1998
|
|
|
1901
1999
|
const canSplit = computed(() => {
|
|
1902
|
-
if (!contextMenuCell.value) return false
|
|
2000
|
+
if (!contextMenuCell.value) {return false}
|
|
1903
2001
|
const cell = contextMenuCell.value
|
|
1904
2002
|
const colspan = Number.parseInt(cell.getAttribute('colspan') || '1')
|
|
1905
2003
|
const rowspan = Number.parseInt(cell.getAttribute('rowspan') || '1')
|
|
1906
|
-
return colspan
|
|
2004
|
+
return 1 < colspan || 1 < rowspan
|
|
1907
2005
|
})
|
|
1908
2006
|
|
|
1909
2007
|
function handleTableContextMenu(event: MouseEvent) {
|
|
@@ -1935,9 +2033,9 @@ const hasRTL = $computed(() => /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(
|
|
|
1935
2033
|
|
|
1936
2034
|
// Computed property to handle height prop
|
|
1937
2035
|
const editorHeight = $computed(() => {
|
|
1938
|
-
if (typeof props.height
|
|
2036
|
+
if ('number' === typeof props.height) {
|
|
1939
2037
|
return `${props.height}px`
|
|
1940
|
-
}
|
|
2038
|
+
}if (typeof props.height === 'string') {
|
|
1941
2039
|
return props.height
|
|
1942
2040
|
}
|
|
1943
2041
|
return '240px' // default height
|
|
@@ -2005,16 +2103,16 @@ function setupTableEditButtons(doc: Document) {
|
|
|
2005
2103
|
if (table.style.marginLeft && table.style.marginRight) {
|
|
2006
2104
|
// Detect current alignment
|
|
2007
2105
|
let alignment = 'left'
|
|
2008
|
-
if (table.style.marginLeft
|
|
2106
|
+
if ('auto' === table.style.marginLeft && 'auto' === table.style.marginRight) {
|
|
2009
2107
|
alignment = 'center'
|
|
2010
|
-
} else if (table.style.marginLeft
|
|
2108
|
+
} else if ('auto' === table.style.marginLeft) {
|
|
2011
2109
|
alignment = 'right'
|
|
2012
2110
|
}
|
|
2013
2111
|
|
|
2014
2112
|
// Apply flex alignment to wrapper
|
|
2015
|
-
if (
|
|
2113
|
+
if ('center' === alignment) {
|
|
2016
2114
|
wrapper.style.alignItems = 'center'
|
|
2017
|
-
} else if (
|
|
2115
|
+
} else if ('right' === alignment) {
|
|
2018
2116
|
wrapper.style.alignItems = 'flex-end'
|
|
2019
2117
|
} else {
|
|
2020
2118
|
wrapper.style.alignItems = 'flex-start'
|
|
@@ -2092,14 +2190,14 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2092
2190
|
}
|
|
2093
2191
|
|
|
2094
2192
|
// If body is completely empty, add a paragraph and return
|
|
2095
|
-
if (!doc.body.innerHTML.trim() || doc.body.innerHTML
|
|
2193
|
+
if (!doc.body.innerHTML.trim() || '' === doc.body.innerHTML) {
|
|
2096
2194
|
const direction = getCurrentDirection()
|
|
2097
2195
|
doc.body.innerHTML = `<p dir="${direction}"><br></p>`
|
|
2098
2196
|
return
|
|
2099
2197
|
}
|
|
2100
2198
|
|
|
2101
2199
|
// Mark body as being normalized to prevent recursive processing
|
|
2102
|
-
if (doc.body.dataset.normalizing
|
|
2200
|
+
if ('true' === doc.body.dataset.normalizing) {
|
|
2103
2201
|
return
|
|
2104
2202
|
}
|
|
2105
2203
|
doc.body.dataset.normalizing = 'true'
|
|
@@ -2115,7 +2213,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2115
2213
|
const parent = node.parentNode as HTMLElement
|
|
2116
2214
|
return (parent === doc.body
|
|
2117
2215
|
&& node.textContent?.trim()
|
|
2118
|
-
&& node.textContent.trim().length
|
|
2216
|
+
&& 0 < node.textContent.trim().length)
|
|
2119
2217
|
? NodeFilter.FILTER_ACCEPT
|
|
2120
2218
|
: NodeFilter.FILTER_REJECT
|
|
2121
2219
|
}
|
|
@@ -2164,13 +2262,13 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2164
2262
|
const paras = Array.from(doc.body.querySelectorAll('p'))
|
|
2165
2263
|
for (let i = 0; i < paras.length; i++) {
|
|
2166
2264
|
const current = paras[i]
|
|
2167
|
-
const isEmpty = !current.textContent?.trim() ||
|
|
2265
|
+
const isEmpty = !current.textContent?.trim() || '<br>' === current.innerHTML
|
|
2168
2266
|
|
|
2169
2267
|
if (isEmpty) {
|
|
2170
2268
|
// Only remove if we have consecutive empty paragraphs at the end
|
|
2171
2269
|
const isLastPara = i === paras.length - 1
|
|
2172
|
-
const prevPara =
|
|
2173
|
-
const isPrevEmpty = prevPara && (!prevPara.textContent?.trim() ||
|
|
2270
|
+
const prevPara = 0 < i ? paras[i - 1] : null
|
|
2271
|
+
const isPrevEmpty = prevPara && (!prevPara.textContent?.trim() || '<br>' === prevPara.innerHTML)
|
|
2174
2272
|
|
|
2175
2273
|
// Keep at least one empty paragraph for cursor placement
|
|
2176
2274
|
if (isPrevEmpty && !isLastPara) {
|
|
@@ -2193,7 +2291,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2193
2291
|
detectAndSetDirection()
|
|
2194
2292
|
|
|
2195
2293
|
// Handle complete content deletion immediately
|
|
2196
|
-
if (!doc.body.innerHTML.trim() || doc.body.innerHTML
|
|
2294
|
+
if (!doc.body.innerHTML.trim() || '' === doc.body.innerHTML) {
|
|
2197
2295
|
if (props.placeholder) {
|
|
2198
2296
|
addPlaceholder()
|
|
2199
2297
|
} else {
|
|
@@ -2220,9 +2318,9 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2220
2318
|
|
|
2221
2319
|
// Handle Enter key
|
|
2222
2320
|
doc.addEventListener('keydown', (e) => {
|
|
2223
|
-
if (e.key
|
|
2321
|
+
if ('Enter' === e.key) {
|
|
2224
2322
|
const selection = doc.getSelection()
|
|
2225
|
-
if (!selection || !selection.rangeCount) return
|
|
2323
|
+
if (!selection || !selection.rangeCount) {return}
|
|
2226
2324
|
|
|
2227
2325
|
const range = selection.getRangeAt(0)
|
|
2228
2326
|
|
|
@@ -2248,13 +2346,13 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2248
2346
|
}
|
|
2249
2347
|
paragraph = (paragraph as Element).closest('p,h1,h2,h3,h4,h5,h6') as HTMLElement
|
|
2250
2348
|
|
|
2251
|
-
if (!paragraph) return
|
|
2349
|
+
if (!paragraph) {return}
|
|
2252
2350
|
|
|
2253
2351
|
// Check if current paragraph is empty and previous paragraph is also empty
|
|
2254
2352
|
const currentIsEmpty = !paragraph.textContent?.trim()
|
|
2255
2353
|
const prevSibling = (paragraph as Element).previousElementSibling as HTMLElement
|
|
2256
2354
|
const prevIsEmpty = prevSibling
|
|
2257
|
-
&& (prevSibling.tagName
|
|
2355
|
+
&& ('P' === prevSibling.tagName)
|
|
2258
2356
|
&& !prevSibling.textContent?.trim()
|
|
2259
2357
|
|
|
2260
2358
|
// If both current and previous paragraphs are empty, don't create another empty paragraph
|
|
@@ -2344,7 +2442,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2344
2442
|
}) // Add a MutationObserver to catch structural changes that might create loose text
|
|
2345
2443
|
const observer = new MutationObserver((mutations) => {
|
|
2346
2444
|
for (const mutation of mutations) {
|
|
2347
|
-
if (mutation.type
|
|
2445
|
+
if ('childList' === mutation.type) {
|
|
2348
2446
|
// Check if any loose text nodes were added to body
|
|
2349
2447
|
Array.from(mutation.addedNodes).forEach((addedNode) => {
|
|
2350
2448
|
if (addedNode.nodeType === Node.TEXT_NODE
|
|
@@ -2360,7 +2458,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2360
2458
|
// Check if a table was added
|
|
2361
2459
|
else if (addedNode.nodeType === Node.ELEMENT_NODE) {
|
|
2362
2460
|
const element = addedNode as HTMLElement
|
|
2363
|
-
if (element.tagName
|
|
2461
|
+
if ('TABLE' === element.tagName) {
|
|
2364
2462
|
console.log('MutationObserver detected new table:', element)
|
|
2365
2463
|
setTimeout(() => {
|
|
2366
2464
|
console.log('Applying default table settings...')
|
|
@@ -2378,7 +2476,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2378
2476
|
}
|
|
2379
2477
|
|
|
2380
2478
|
// Also apply direction to list items if it's a list
|
|
2381
|
-
if (
|
|
2479
|
+
if ('UL' === element.tagName || 'OL' === element.tagName) {
|
|
2382
2480
|
const listItems = element.querySelectorAll('li')
|
|
2383
2481
|
listItems.forEach((li) => {
|
|
2384
2482
|
if (!li.dir) {
|
|
@@ -2445,7 +2543,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2445
2543
|
|
|
2446
2544
|
// Get current selection
|
|
2447
2545
|
const selection = doc.getSelection()
|
|
2448
|
-
if (!selection) return
|
|
2546
|
+
if (!selection) {return}
|
|
2449
2547
|
|
|
2450
2548
|
// Create a range that selects the entire link
|
|
2451
2549
|
const range = doc.createRange()
|
|
@@ -2455,7 +2553,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2455
2553
|
|
|
2456
2554
|
// Populate the form with existing link data
|
|
2457
2555
|
linkForm.value.url = link.href
|
|
2458
|
-
linkForm.value.openInNewTab = link.target
|
|
2556
|
+
linkForm.value.openInNewTab = '_blank' === link.target
|
|
2459
2557
|
|
|
2460
2558
|
// Store the link data for editing
|
|
2461
2559
|
pendingLinkData = {
|
|
@@ -2509,16 +2607,11 @@ async function initEditor() {
|
|
|
2509
2607
|
isInitializing.value = true
|
|
2510
2608
|
|
|
2511
2609
|
try {
|
|
2512
|
-
// Get the --input-color CSS variable from the parent page
|
|
2513
|
-
const computedStyle = getComputedStyle(document.documentElement)
|
|
2514
|
-
const inputColor = computedStyle.getPropertyValue('--input-color').trim()
|
|
2515
|
-
const defaultTextColor = inputColor || 'inherit'
|
|
2516
|
-
|
|
2517
2610
|
// Use basic embedded styles for better compatibility
|
|
2518
2611
|
// We copy CSS variables to the iframe so it can use them
|
|
2519
2612
|
const editorStylesContent = `
|
|
2520
2613
|
:root {
|
|
2521
|
-
--input-color: ${
|
|
2614
|
+
--input-color: ${currentInputColor.value || '#000'};
|
|
2522
2615
|
}
|
|
2523
2616
|
body {
|
|
2524
2617
|
margin: 0;
|
|
@@ -2526,11 +2619,16 @@ async function initEditor() {
|
|
|
2526
2619
|
min-height: 200px;
|
|
2527
2620
|
font-family: sans-serif !important;
|
|
2528
2621
|
line-height: 1.5;
|
|
2529
|
-
color: ${
|
|
2622
|
+
color: ${currentTextColor.value};
|
|
2530
2623
|
background: transparent;
|
|
2531
2624
|
max-width: 1060px;
|
|
2532
2625
|
margin: 0 auto;
|
|
2533
2626
|
}
|
|
2627
|
+
|
|
2628
|
+
/* Ensure all text elements inherit the theme color */
|
|
2629
|
+
p, h1, h2, h3, h4, h5, h6, div, span, li, td, th {
|
|
2630
|
+
color: inherit !important;
|
|
2631
|
+
}
|
|
2534
2632
|
table {
|
|
2535
2633
|
border-collapse: collapse;
|
|
2536
2634
|
margin-bottom: 1rem;
|
|
@@ -2624,7 +2722,7 @@ async function initEditor() {
|
|
|
2624
2722
|
|
|
2625
2723
|
// Write the complete HTML document to the iframe
|
|
2626
2724
|
const doc = iframe.value.contentDocument || iframe.value.contentWindow?.document
|
|
2627
|
-
if (!doc) return
|
|
2725
|
+
if (!doc) {return}
|
|
2628
2726
|
|
|
2629
2727
|
// First write the content
|
|
2630
2728
|
doc.open()
|
|
@@ -2653,7 +2751,7 @@ async function initEditor() {
|
|
|
2653
2751
|
}
|
|
2654
2752
|
|
|
2655
2753
|
// Also apply direction to list items
|
|
2656
|
-
if (
|
|
2754
|
+
if ('UL' === htmlElement.tagName || 'OL' === htmlElement.tagName) {
|
|
2657
2755
|
const listItems = htmlElement.querySelectorAll('li')
|
|
2658
2756
|
listItems.forEach((li) => {
|
|
2659
2757
|
const listItem = li as HTMLElement
|
|
@@ -2677,7 +2775,7 @@ async function initEditor() {
|
|
|
2677
2775
|
// Clear all formatting by removing styles and replacing with plain text
|
|
2678
2776
|
const elements = doc.body.querySelectorAll('*')
|
|
2679
2777
|
elements.forEach((el) => {
|
|
2680
|
-
if (
|
|
2778
|
+
if ('P' !== el.tagName && 'BR' !== el.tagName) {
|
|
2681
2779
|
const textContent = el.textContent || ''
|
|
2682
2780
|
if (textContent.trim()) {
|
|
2683
2781
|
const p = doc.createElement('p')
|
|
@@ -2686,10 +2784,10 @@ async function initEditor() {
|
|
|
2686
2784
|
} else {
|
|
2687
2785
|
el.remove()
|
|
2688
2786
|
}
|
|
2689
|
-
} else if (el.tagName
|
|
2787
|
+
} else if ('P' === el.tagName) {
|
|
2690
2788
|
// Remove all attributes from paragraphs
|
|
2691
2789
|
Array.from(el.attributes).forEach((attr) => {
|
|
2692
|
-
if (attr.name
|
|
2790
|
+
if ('dir' !== attr.name) {
|
|
2693
2791
|
el.removeAttribute(attr.name)
|
|
2694
2792
|
}
|
|
2695
2793
|
})
|
|
@@ -2713,7 +2811,7 @@ async function initEditor() {
|
|
|
2713
2811
|
doc.addEventListener('click', (e) => {
|
|
2714
2812
|
setTimeout(() => {
|
|
2715
2813
|
const selection = doc.getSelection()
|
|
2716
|
-
if (!selection || selection.rangeCount
|
|
2814
|
+
if (!selection || 0 === selection.rangeCount || selection.getRangeAt(0).collapsed) {
|
|
2717
2815
|
hideInlineToolbar()
|
|
2718
2816
|
}
|
|
2719
2817
|
}, 10)
|
|
@@ -2724,7 +2822,7 @@ async function initEditor() {
|
|
|
2724
2822
|
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Escape'].includes(e.key)) {
|
|
2725
2823
|
setTimeout(() => {
|
|
2726
2824
|
const selection = doc.getSelection()
|
|
2727
|
-
if (!selection || selection.rangeCount
|
|
2825
|
+
if (!selection || 0 === selection.rangeCount || selection.getRangeAt(0).collapsed) {
|
|
2728
2826
|
hideInlineToolbar()
|
|
2729
2827
|
}
|
|
2730
2828
|
}, 10)
|
|
@@ -2818,11 +2916,16 @@ async function initEditor() {
|
|
|
2818
2916
|
}
|
|
2819
2917
|
|
|
2820
2918
|
// Only focus if autofocus is explicitly set to true
|
|
2821
|
-
if (props.autofocus
|
|
2919
|
+
if (true === props.autofocus) {
|
|
2822
2920
|
doc.body.focus()
|
|
2823
2921
|
}
|
|
2824
2922
|
|
|
2825
2923
|
hasInitialized.value = true
|
|
2924
|
+
|
|
2925
|
+
// Update colors after initialization
|
|
2926
|
+
setTimeout(() => {
|
|
2927
|
+
updateIframeColors()
|
|
2928
|
+
}, 100)
|
|
2826
2929
|
} catch (error) {
|
|
2827
2930
|
// Keep only this error log for debugging critical issues
|
|
2828
2931
|
console.error('Error during editor initialization:', error)
|
|
@@ -2831,11 +2934,74 @@ async function initEditor() {
|
|
|
2831
2934
|
}
|
|
2832
2935
|
}
|
|
2833
2936
|
|
|
2937
|
+
// Function to update CSS colors in the iframe
|
|
2938
|
+
function updateIframeColors() {
|
|
2939
|
+
console.log('🎯 updateIframeColors called', {
|
|
2940
|
+
hasIframe: !!iframe.value,
|
|
2941
|
+
hasContentDocument: !!iframe.value?.contentDocument,
|
|
2942
|
+
hasInitialized: hasInitialized.value
|
|
2943
|
+
})
|
|
2944
|
+
|
|
2945
|
+
if (!iframe.value?.contentDocument || null === iframe.value.contentDocument) {
|
|
2946
|
+
console.warn('❌ No iframe or contentDocument')
|
|
2947
|
+
return
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
const doc = iframe.value.contentDocument
|
|
2951
|
+
let styleElement = doc.getElementById('editor-theme-styles') as HTMLStyleElement
|
|
2952
|
+
|
|
2953
|
+
if (!styleElement) {
|
|
2954
|
+
styleElement = doc.createElement('style')
|
|
2955
|
+
styleElement.id = 'editor-theme-styles'
|
|
2956
|
+
doc.head.appendChild(styleElement)
|
|
2957
|
+
console.log('✅ Created new style element')
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
const fontSize = props.fontSize ? ('number' === typeof props.fontSize ? `${props.fontSize}px` : props.fontSize) : '16px'
|
|
2961
|
+
|
|
2962
|
+
const css = `
|
|
2963
|
+
:root {
|
|
2964
|
+
--input-color: ${currentInputColor.value || '#000'};
|
|
2965
|
+
--richtext-font-size: ${fontSize};
|
|
2966
|
+
}
|
|
2967
|
+
body {
|
|
2968
|
+
color: ${currentTextColor.value} !important;
|
|
2969
|
+
font-size: ${fontSize} !important;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
/* Ensure all text elements inherit the color and font size */
|
|
2973
|
+
p, h1, h2, h3, h4, h5, h6, div, span, li, td, th {
|
|
2974
|
+
color: inherit !important;
|
|
2975
|
+
font-size: inherit !important;
|
|
2976
|
+
}
|
|
2977
|
+
`
|
|
2978
|
+
|
|
2979
|
+
styleElement.textContent = css
|
|
2980
|
+
console.log('🎨 Updated iframe colors:', {
|
|
2981
|
+
inputColor: currentInputColor.value,
|
|
2982
|
+
textColor: currentTextColor.value,
|
|
2983
|
+
css: css.trim()
|
|
2984
|
+
})
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
// Watch for theme changes and update iframe colors
|
|
2988
|
+
watch([currentInputColor, currentTextColor], (newValues, oldValues) => {
|
|
2989
|
+
console.log('🔄 Colors changed:', {
|
|
2990
|
+
newValues,
|
|
2991
|
+
oldValues,
|
|
2992
|
+
hasInitialized: hasInitialized.value
|
|
2993
|
+
})
|
|
2994
|
+
|
|
2995
|
+
if (hasInitialized.value) {
|
|
2996
|
+
updateIframeColors()
|
|
2997
|
+
}
|
|
2998
|
+
}, { flush: 'post' })
|
|
2999
|
+
|
|
2834
3000
|
// Reset initialization state when content changes significantly
|
|
2835
3001
|
watch(() => props.modelValue, (newValue, oldValue) => {
|
|
2836
3002
|
if (newValue !== editor.state.content) {
|
|
2837
3003
|
// Only reset if content change is significant (not just minor edits)
|
|
2838
|
-
if (!oldValue || Math.abs(newValue.length - oldValue.length)
|
|
3004
|
+
if (!oldValue || 50 < Math.abs(newValue.length - oldValue.length)) {
|
|
2839
3005
|
hasInitialized.value = false
|
|
2840
3006
|
// For external changes, update content directly but then push to history
|
|
2841
3007
|
editor.state.content = newValue
|
|
@@ -2870,10 +3036,10 @@ watch(() => editor.state.content, (newValue) => {
|
|
|
2870
3036
|
watch(() => tableForm.value.alignment, (newAlignment) => {
|
|
2871
3037
|
if (pendingTableData?.existingTable) {
|
|
2872
3038
|
const table = pendingTableData.existingTable
|
|
2873
|
-
if (
|
|
3039
|
+
if ('center' === newAlignment) {
|
|
2874
3040
|
table.style.marginLeft = 'auto'
|
|
2875
3041
|
table.style.marginRight = 'auto'
|
|
2876
|
-
} else if (
|
|
3042
|
+
} else if ('right' === newAlignment) {
|
|
2877
3043
|
table.style.marginLeft = 'auto'
|
|
2878
3044
|
table.style.marginRight = '0'
|
|
2879
3045
|
} else {
|
|
@@ -2894,13 +3060,13 @@ function handleGlobalClick() {
|
|
|
2894
3060
|
}
|
|
2895
3061
|
|
|
2896
3062
|
// Add event listener when component mounts
|
|
2897
|
-
if (typeof window
|
|
3063
|
+
if ('undefined' !== typeof window) {
|
|
2898
3064
|
window.addEventListener('click', handleGlobalClick)
|
|
2899
3065
|
}
|
|
2900
3066
|
|
|
2901
3067
|
// Cleanup event listener
|
|
2902
3068
|
onBeforeUnmount(() => {
|
|
2903
|
-
if (typeof window
|
|
3069
|
+
if ('undefined' !== typeof window) {
|
|
2904
3070
|
window.removeEventListener('click', handleGlobalClick)
|
|
2905
3071
|
}
|
|
2906
3072
|
})
|
|
@@ -3412,7 +3578,6 @@ defineExpose({
|
|
|
3412
3578
|
min-width: calc(var(--input-height) * 3);
|
|
3413
3579
|
width: 100%;
|
|
3414
3580
|
}
|
|
3415
|
-
|
|
3416
3581
|
.rich-text-editor--basic .content-area:hover {
|
|
3417
3582
|
outline-color: rgba(0, 0, 0, 0.05);
|
|
3418
3583
|
box-shadow: inset 0 0 8px #00000018;
|
|
@@ -3423,6 +3588,7 @@ defineExpose({
|
|
|
3423
3588
|
.content-area span,
|
|
3424
3589
|
.content-area li {
|
|
3425
3590
|
line-height: 1.65;
|
|
3591
|
+
font-size: var(--richtext-font-size, 16px);
|
|
3426
3592
|
}
|
|
3427
3593
|
</style>
|
|
3428
3594
|
|
|
@@ -3452,6 +3618,7 @@ defineExpose({
|
|
|
3452
3618
|
.preview-area {
|
|
3453
3619
|
flex: 1;
|
|
3454
3620
|
background: var(--bgl-richtext-color);
|
|
3621
|
+
font-size: var(--richtext-font-size, 16px);
|
|
3455
3622
|
}
|
|
3456
3623
|
|
|
3457
3624
|
.split-view {
|
|
@@ -3465,6 +3632,7 @@ defineExpose({
|
|
|
3465
3632
|
border: none;
|
|
3466
3633
|
outline: none;
|
|
3467
3634
|
background: transparent;
|
|
3635
|
+
font-size: var(--richtext-font-size, 16px);
|
|
3468
3636
|
}
|
|
3469
3637
|
|
|
3470
3638
|
.html-editor {
|