@bagelink/vue 1.6.43 → 1.6.49
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 +18 -19
- package/bin/utils.ts +4 -4
- package/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/Alert.vue.d.ts.map +1 -1
- package/dist/components/BglVideo.vue.d.ts.map +1 -1
- package/dist/components/Card.vue.d.ts.map +1 -1
- package/dist/components/Carousel.vue.d.ts +2 -2
- package/dist/components/Carousel.vue.d.ts.map +1 -1
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/Flag.vue.d.ts.map +1 -1
- package/dist/components/IframeVue.vue.d.ts.map +1 -1
- package/dist/components/ListItem.vue.d.ts.map +1 -1
- package/dist/components/Loading.vue.d.ts.map +1 -1
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/ModalForm.vue.d.ts.map +1 -1
- package/dist/components/NavBar.vue.d.ts +1 -1
- package/dist/components/Pill.vue.d.ts.map +1 -1
- package/dist/components/Swiper.vue.d.ts +12 -4
- package/dist/components/Swiper.vue.d.ts.map +1 -1
- package/dist/components/Zoomer.vue.d.ts.map +1 -1
- package/dist/components/analytics/LineChart.vue.d.ts.map +1 -1
- package/dist/components/analytics/PieChart.vue.d.ts +2 -1
- package/dist/components/analytics/PieChart.vue.d.ts.map +1 -1
- package/dist/components/analytics/index.d.ts +1 -1
- package/dist/components/analytics/index.d.ts.map +1 -1
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/form/BglMultiStepForm.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RadioGroup.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RangeInput.vue.d.ts +11 -11
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/components/TableGridSelector.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
- package/dist/components/layout/AppContent.vue.d.ts.map +1 -1
- package/dist/components/layout/AppSidebar.vue.d.ts +1 -0
- package/dist/components/layout/AppSidebar.vue.d.ts.map +1 -1
- package/dist/components/layout/Layout.vue.d.ts.map +1 -1
- package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
- package/dist/components/layout/index.d.ts +3 -3
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
- package/dist/index.cjs +24 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +1530 -1404
- package/dist/plugins/modalTypes.d.ts +1 -8
- package/dist/plugins/modalTypes.d.ts.map +1 -1
- package/dist/plugins/useModal.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -2
- package/src/components/AccordionItem.vue +13 -13
- package/src/components/AddToCalendar.vue +1 -1
- package/src/components/AddressSearch.vue +9 -8
- package/src/components/Alert.vue +2 -1
- package/src/components/Badge.vue +5 -5
- package/src/components/BglVideo.vue +44 -45
- package/src/components/Btn.vue +15 -15
- package/src/components/Card.vue +10 -8
- package/src/components/Carousel.vue +159 -162
- package/src/components/DataPreview.vue +1 -1
- package/src/components/DragOver.vue +6 -6
- package/src/components/Dropdown.vue +39 -38
- package/src/components/Flag.vue +7 -6
- package/src/components/Icon/Icon.vue +22 -22
- package/src/components/IframeVue.vue +5 -5
- package/src/components/Image.vue +17 -17
- package/src/components/ImportData.vue +79 -79
- package/src/components/ListItem.vue +12 -11
- package/src/components/Loading.vue +10 -9
- package/src/components/MapEmbed/Index.vue +24 -24
- package/src/components/Modal.vue +11 -9
- package/src/components/ModalForm.vue +15 -11
- package/src/components/NavBar.vue +6 -6
- package/src/components/Pagination.vue +27 -27
- package/src/components/Pill.vue +11 -12
- package/src/components/Rating.vue +2 -2
- package/src/components/Slider.vue +75 -75
- package/src/components/Spreadsheet/Index.vue +34 -34
- package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
- package/src/components/Swiper.vue +4 -4
- package/src/components/Zoomer.vue +282 -182
- package/src/components/analytics/BarChart.vue +6 -6
- package/src/components/analytics/KpiCard.vue +2 -2
- package/src/components/analytics/LineChart.vue +63 -61
- package/src/components/analytics/PieChart.vue +104 -90
- package/src/components/analytics/index.ts +2 -2
- package/src/components/calendar/CalendarPopover.vue +1 -1
- package/src/components/calendar/Index.vue +1 -1
- package/src/components/calendar/views/AgendaView.vue +3 -3
- 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 +4 -4
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +15 -15
- package/src/components/dataTable/useTableSelection.ts +15 -15
- package/src/components/dataTable/useTableVirtualization.ts +1 -1
- package/src/components/draggable/useDraggable.ts +42 -42
- package/src/components/form/BagelForm.vue +15 -15
- package/src/components/form/BglFieldSet.vue +5 -3
- package/src/components/form/BglMultiStepForm.vue +20 -21
- package/src/components/form/inputs/CheckInput.vue +2 -2
- 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/ColorInput.vue +5 -4
- package/src/components/form/inputs/DateInput.vue +8 -9
- package/src/components/form/inputs/DatePicker.vue +24 -24
- package/src/components/form/inputs/EmailInput.vue +24 -24
- package/src/components/form/inputs/NumberInput.vue +26 -26
- package/src/components/form/inputs/OTP.vue +7 -7
- package/src/components/form/inputs/PasswordInput.vue +3 -2
- package/src/components/form/inputs/RadioGroup.vue +28 -25
- package/src/components/form/inputs/RadioPillsInput.vue +12 -12
- package/src/components/form/inputs/RangeInput.vue +21 -21
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +107 -92
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +64 -64
- package/src/components/form/inputs/RichText/components/gridBox.vue +10 -8
- 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 +138 -138
- package/src/components/form/inputs/RichText/utils/commands.ts +84 -85
- 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 +7 -7
- 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 +54 -54
- package/src/components/form/inputs/SignaturePad.vue +40 -40
- package/src/components/form/inputs/TableField.vue +1 -1
- package/src/components/form/inputs/TelInput.vue +54 -53
- package/src/components/form/inputs/TextInput.vue +19 -19
- package/src/components/form/inputs/ToggleInput.vue +2 -2
- package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
- package/src/components/form/useBagelFormState.ts +5 -5
- package/src/components/layout/AppContent.vue +6 -3
- package/src/components/layout/AppLayout.vue +2 -2
- package/src/components/layout/AppSidebar.vue +83 -16
- package/src/components/layout/Layout.vue +12 -10
- package/src/components/layout/SidebarMenu.vue +4 -4
- package/src/components/layout/TabbedLayout.vue +17 -17
- package/src/components/layout/Tabs.vue +4 -5
- package/src/components/layout/TabsNav.vue +14 -14
- package/src/components/layout/index.ts +3 -5
- package/src/components/lightbox/Lightbox.vue +276 -126
- package/src/components/lightbox/index.ts +8 -8
- package/src/composables/index.ts +8 -8
- package/src/composables/useAddToCalendar.ts +13 -13
- package/src/composables/useDevice.ts +2 -2
- package/src/composables/useFormField.ts +4 -4
- package/src/composables/usePolling.ts +8 -8
- package/src/composables/useSchemaField.ts +38 -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/index.ts +1 -0
- package/src/plugins/bagel.ts +4 -4
- package/src/plugins/modalTypes.ts +1 -8
- package/src/plugins/useModal.ts +43 -18
- package/src/styles/layout.css +1 -1
- package/src/types/index.ts +1 -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/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 +0 -2
|
@@ -61,7 +61,7 @@ const currentInputColor = computed(() => {
|
|
|
61
61
|
// Force reactivity by using forceUpdate
|
|
62
62
|
void forceUpdate.value
|
|
63
63
|
|
|
64
|
-
if ('undefined'
|
|
64
|
+
if (typeof document !== 'undefined') {
|
|
65
65
|
const computedStyle = getComputedStyle(document.documentElement)
|
|
66
66
|
const color = computedStyle.getPropertyValue('--input-color').trim()
|
|
67
67
|
console.log('🎨 currentInputColor computed:', color, 'forceUpdate:', forceUpdate.value)
|
|
@@ -72,7 +72,7 @@ const currentInputColor = computed(() => {
|
|
|
72
72
|
|
|
73
73
|
const currentTextColor = computed(() => {
|
|
74
74
|
const inputColor = currentInputColor.value
|
|
75
|
-
const textColor = props.textColor || (inputColor &&
|
|
75
|
+
const textColor = props.textColor || (inputColor && inputColor.length > 0 && inputColor !== '#000' ? inputColor : 'inherit')
|
|
76
76
|
console.log('🎨 currentTextColor computed:', textColor, 'from inputColor:', inputColor)
|
|
77
77
|
return textColor
|
|
78
78
|
})
|
|
@@ -81,15 +81,15 @@ const currentTextColor = computed(() => {
|
|
|
81
81
|
let themeObserver: MutationObserver | null = null
|
|
82
82
|
|
|
83
83
|
onMounted(() => {
|
|
84
|
-
if ('undefined'
|
|
84
|
+
if (typeof document !== 'undefined') {
|
|
85
85
|
themeObserver = new MutationObserver((mutations) => {
|
|
86
86
|
let shouldUpdate = false
|
|
87
87
|
mutations.forEach((mutation) => {
|
|
88
|
-
if ('attributes'
|
|
88
|
+
if (mutation.type === 'attributes') {
|
|
89
89
|
const { attributeName } = mutation
|
|
90
|
-
if ('data-theme'
|
|
91
|
-
|| 'class'
|
|
92
|
-
|| 'style'
|
|
90
|
+
if (attributeName === 'data-theme'
|
|
91
|
+
|| attributeName === 'class'
|
|
92
|
+
|| attributeName === 'style') {
|
|
93
93
|
shouldUpdate = true
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -129,7 +129,7 @@ onBeforeUnmount(() => {
|
|
|
129
129
|
})
|
|
130
130
|
|
|
131
131
|
// Global testing functions
|
|
132
|
-
if ('undefined'
|
|
132
|
+
if (typeof window !== 'undefined') {
|
|
133
133
|
(window as any).testRichTextTheme = () => {
|
|
134
134
|
console.log('🧪 Testing RichText theme:', {
|
|
135
135
|
currentInputColor: currentInputColor.value,
|
|
@@ -152,13 +152,13 @@ if ('undefined' !== typeof window) {
|
|
|
152
152
|
|
|
153
153
|
// Computed properties for UI control
|
|
154
154
|
const shouldShowToolbar = computed(() => {
|
|
155
|
-
if (props.hideToolbar) {return false}
|
|
156
|
-
if (props.basic) {return false}
|
|
155
|
+
if (props.hideToolbar) { return false }
|
|
156
|
+
if (props.basic) { return false }
|
|
157
157
|
return true
|
|
158
158
|
})
|
|
159
159
|
|
|
160
160
|
const shouldShowInlineToolbar = computed(() => {
|
|
161
|
-
if (props.hideInlineToolbar) {return false}
|
|
161
|
+
if (props.hideInlineToolbar) { return false }
|
|
162
162
|
return true
|
|
163
163
|
})
|
|
164
164
|
|
|
@@ -337,7 +337,7 @@ const tablePreviewHtml = computed(() => {
|
|
|
337
337
|
border: ${form.borderWidth}px solid ${form.borderColor};
|
|
338
338
|
text-align: ${form.alignment};
|
|
339
339
|
${form.fixedLayout ? `width: ${100 / form.cols}%;` : ''}
|
|
340
|
-
${form.alternateRows &&
|
|
340
|
+
${form.alternateRows && i % 2 === 1
|
|
341
341
|
? `background-color: ${form.alternateRowBgColor}; color: ${form.alternateRowTextColor};`
|
|
342
342
|
: `background-color: ${form.cellBgColor}; color: ${form.cellTextColor};`}
|
|
343
343
|
`
|
|
@@ -399,7 +399,7 @@ function detectAndSetDirection() {
|
|
|
399
399
|
// Function to get current direction based on content
|
|
400
400
|
function getCurrentDirection() {
|
|
401
401
|
const { doc } = editor.state
|
|
402
|
-
if (!doc?.body) {return 'ltr'}
|
|
402
|
+
if (!doc?.body) { return 'ltr' }
|
|
403
403
|
|
|
404
404
|
const allText = doc.body.textContent || ''
|
|
405
405
|
const firstChars = allText.trim().substring(0, 10)
|
|
@@ -410,7 +410,7 @@ function getCurrentDirection() {
|
|
|
410
410
|
|
|
411
411
|
// Helper function to update content with history tracking
|
|
412
412
|
function updateContentWithHistory(doc: Document, skipHistory = false) {
|
|
413
|
-
if (!doc) {return}
|
|
413
|
+
if (!doc) { return }
|
|
414
414
|
|
|
415
415
|
const newContent = doc.body.innerHTML
|
|
416
416
|
if (newContent !== editor.state.content) {
|
|
@@ -420,7 +420,7 @@ function updateContentWithHistory(doc: Document, skipHistory = false) {
|
|
|
420
420
|
// Clear redo stack when new content is added
|
|
421
421
|
editor.state.redoStack = []
|
|
422
422
|
// Limit undo stack size to prevent memory issues
|
|
423
|
-
if (
|
|
423
|
+
if (editor.state.undoStack.length > 50) {
|
|
424
424
|
editor.state.undoStack.shift()
|
|
425
425
|
}
|
|
426
426
|
}
|
|
@@ -472,10 +472,10 @@ function showInlineToolbarForSelection() {
|
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
const { doc } = editor.state
|
|
475
|
-
if (!doc) {return}
|
|
475
|
+
if (!doc) { return }
|
|
476
476
|
|
|
477
477
|
const selection = doc.getSelection()
|
|
478
|
-
if (!selection ||
|
|
478
|
+
if (!selection || selection.rangeCount === 0) {
|
|
479
479
|
hideInlineToolbar()
|
|
480
480
|
return
|
|
481
481
|
}
|
|
@@ -529,14 +529,14 @@ function hideInlineToolbar() {
|
|
|
529
529
|
|
|
530
530
|
// Function to run inline toolbar action
|
|
531
531
|
function runInlineAction(actionName: string) {
|
|
532
|
-
if (!inlineToolbarSelection.value) {return}
|
|
532
|
+
if (!inlineToolbarSelection.value) { return }
|
|
533
533
|
|
|
534
534
|
const { doc } = editor.state
|
|
535
|
-
if (!doc) {return}
|
|
535
|
+
if (!doc) { return }
|
|
536
536
|
|
|
537
537
|
// Get the stored range
|
|
538
538
|
const storedRange = (inlineToolbarSelection.value as any)._storedRange as Range
|
|
539
|
-
if (!storedRange) {return}
|
|
539
|
+
if (!storedRange) { return }
|
|
540
540
|
|
|
541
541
|
// Restore selection using the stored range
|
|
542
542
|
const selection = doc.getSelection()
|
|
@@ -551,7 +551,7 @@ function runInlineAction(actionName: string) {
|
|
|
551
551
|
// Keep the toolbar visible but update the stored selection
|
|
552
552
|
setTimeout(() => {
|
|
553
553
|
const newSelection = doc.getSelection()
|
|
554
|
-
if (newSelection &&
|
|
554
|
+
if (newSelection && newSelection.rangeCount > 0) {
|
|
555
555
|
const newRange = newSelection.getRangeAt(0)
|
|
556
556
|
if (!newRange.collapsed) {
|
|
557
557
|
; (inlineToolbarSelection.value as any)._storedRange = newRange.cloneRange()
|
|
@@ -572,7 +572,7 @@ function showTooltipMessage(message: string, x?: number, y?: number) {
|
|
|
572
572
|
// If coordinates not provided, try to get cursor position
|
|
573
573
|
if (x === undefined || y === undefined) {
|
|
574
574
|
const selection = editor.state.doc?.getSelection()
|
|
575
|
-
if (selection &&
|
|
575
|
+
if (selection && selection.rangeCount > 0) {
|
|
576
576
|
const range = selection.getRangeAt(0)
|
|
577
577
|
const rect = range.getBoundingClientRect()
|
|
578
578
|
// Get iframe offset
|
|
@@ -608,20 +608,20 @@ function openLinkModal(selection: Selection, range: Range, existingLink: HTMLAnc
|
|
|
608
608
|
pendingLinkData = { selection, range, existingLink }
|
|
609
609
|
linkForm.value = {
|
|
610
610
|
url: existingLink?.href || '',
|
|
611
|
-
openInNewTab: '_self'
|
|
611
|
+
openInNewTab: existingLink?.target !== '_self'
|
|
612
612
|
}
|
|
613
613
|
showLinkModal.value = true
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
// Function to submit link
|
|
617
617
|
function submitLink() {
|
|
618
|
-
if (!pendingLinkData || !linkForm.value.url) {return}
|
|
618
|
+
if (!pendingLinkData || !linkForm.value.url) { return }
|
|
619
619
|
|
|
620
620
|
const { selection, range, existingLink } = pendingLinkData
|
|
621
621
|
const { url, openInNewTab } = linkForm.value
|
|
622
622
|
const { doc } = editor.state
|
|
623
623
|
|
|
624
|
-
if (!doc) {return}
|
|
624
|
+
if (!doc) { return }
|
|
625
625
|
|
|
626
626
|
if (existingLink) {
|
|
627
627
|
// Update existing link
|
|
@@ -668,7 +668,7 @@ function submitLink() {
|
|
|
668
668
|
|
|
669
669
|
// Function to visit link
|
|
670
670
|
function visitLink() {
|
|
671
|
-
if (!linkForm.value.url || !isValidUrl(linkForm.value.url)) {return}
|
|
671
|
+
if (!linkForm.value.url || !isValidUrl(linkForm.value.url)) { return }
|
|
672
672
|
|
|
673
673
|
let url = linkForm.value.url.trim()
|
|
674
674
|
|
|
@@ -686,7 +686,7 @@ function visitLink() {
|
|
|
686
686
|
|
|
687
687
|
// Function to validate URL
|
|
688
688
|
function isValidUrl(url: string): boolean {
|
|
689
|
-
if (!url ||
|
|
689
|
+
if (!url || url.trim() === '') { return false }
|
|
690
690
|
|
|
691
691
|
try {
|
|
692
692
|
URL.canParse(url)
|
|
@@ -705,12 +705,12 @@ function isValidUrl(url: string): boolean {
|
|
|
705
705
|
// Function to open image modal
|
|
706
706
|
function openImageModal(existingImage: HTMLElement | null = null) {
|
|
707
707
|
const { doc } = editor.state
|
|
708
|
-
if (!doc) {return}
|
|
708
|
+
if (!doc) { return }
|
|
709
709
|
|
|
710
710
|
// Get current selection for new images
|
|
711
711
|
if (!existingImage) {
|
|
712
712
|
const selection = doc.getSelection()
|
|
713
|
-
if (!selection || !selection.rangeCount) {return}
|
|
713
|
+
if (!selection || !selection.rangeCount) { return }
|
|
714
714
|
const range = selection.getRangeAt(0)
|
|
715
715
|
pendingImageData = { selection, range, existingImage: null }
|
|
716
716
|
} else {
|
|
@@ -754,10 +754,10 @@ function openImageModal(existingImage: HTMLElement | null = null) {
|
|
|
754
754
|
|
|
755
755
|
// Function to submit image
|
|
756
756
|
function submitImage() {
|
|
757
|
-
if (!imageForm.value.src || !pendingImageData) {return}
|
|
757
|
+
if (!imageForm.value.src || !pendingImageData) { return }
|
|
758
758
|
|
|
759
759
|
const { doc } = editor.state
|
|
760
|
-
if (!doc) {return}
|
|
760
|
+
if (!doc) { return }
|
|
761
761
|
|
|
762
762
|
const { existingImage } = pendingImageData
|
|
763
763
|
|
|
@@ -780,7 +780,7 @@ function submitImage() {
|
|
|
780
780
|
|
|
781
781
|
if (imageForm.value.height) {
|
|
782
782
|
img.setAttribute('data-height', 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') ||
|
|
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') || imageForm.value.height === 'auto') {
|
|
784
784
|
img.style.height = imageForm.value.height
|
|
785
785
|
} else {
|
|
786
786
|
img.style.height = `${imageForm.value.height}px`
|
|
@@ -811,7 +811,7 @@ function submitImage() {
|
|
|
811
811
|
// Create or update figure/image - always wrap in figure
|
|
812
812
|
let elementToUpdate: HTMLElement
|
|
813
813
|
if (existingImage) {
|
|
814
|
-
if (
|
|
814
|
+
if (existingImage.tagName.toLowerCase() === 'img') {
|
|
815
815
|
// Converting standalone image to figure (always)
|
|
816
816
|
const figure = doc.createElement('figure')
|
|
817
817
|
figure.className = 'image-figure'
|
|
@@ -876,12 +876,12 @@ function submitImage() {
|
|
|
876
876
|
// Function to open embed modal
|
|
877
877
|
function openEmbedModal(existingEmbed: HTMLElement | null = null) {
|
|
878
878
|
const { doc } = editor.state
|
|
879
|
-
if (!doc) {return}
|
|
879
|
+
if (!doc) { return }
|
|
880
880
|
|
|
881
881
|
// Get current selection for new embeds
|
|
882
882
|
if (!existingEmbed) {
|
|
883
883
|
const selection = doc.getSelection()
|
|
884
|
-
if (!selection || !selection.rangeCount) {return}
|
|
884
|
+
if (!selection || !selection.rangeCount) { return }
|
|
885
885
|
const range = selection.getRangeAt(0)
|
|
886
886
|
pendingEmbedData = { selection, range, existingEmbed: null }
|
|
887
887
|
} else {
|
|
@@ -935,10 +935,10 @@ function extractEmbedUrl(input: string): string {
|
|
|
935
935
|
|
|
936
936
|
// Function to submit embed
|
|
937
937
|
function submitEmbed() {
|
|
938
|
-
if (!embedForm.value.src || !pendingEmbedData) {return}
|
|
938
|
+
if (!embedForm.value.src || !pendingEmbedData) { return }
|
|
939
939
|
|
|
940
940
|
const { doc } = editor.state
|
|
941
|
-
if (!doc) {return}
|
|
941
|
+
if (!doc) { return }
|
|
942
942
|
|
|
943
943
|
const { existingEmbed } = pendingEmbedData
|
|
944
944
|
|
|
@@ -1015,12 +1015,12 @@ function submitEmbed() {
|
|
|
1015
1015
|
// Function to open video modal
|
|
1016
1016
|
function openVideoModal(existingVideo: HTMLElement | null = null) {
|
|
1017
1017
|
const { doc } = editor.state
|
|
1018
|
-
if (!doc) {return}
|
|
1018
|
+
if (!doc) { return }
|
|
1019
1019
|
|
|
1020
1020
|
// Get current selection for new videos
|
|
1021
1021
|
if (!existingVideo) {
|
|
1022
1022
|
const selection = doc.getSelection()
|
|
1023
|
-
if (!selection || !selection.rangeCount) {return}
|
|
1023
|
+
if (!selection || !selection.rangeCount) { return }
|
|
1024
1024
|
const range = selection.getRangeAt(0)
|
|
1025
1025
|
pendingVideoData = { selection, range, existingVideo: null }
|
|
1026
1026
|
} else {
|
|
@@ -1035,14 +1035,14 @@ function openVideoModal(existingVideo: HTMLElement | null = null) {
|
|
|
1035
1035
|
if (existingVideo) {
|
|
1036
1036
|
// Populate form with existing video data
|
|
1037
1037
|
const container = existingVideo.querySelector('.video-container')
|
|
1038
|
-
const isCustom =
|
|
1038
|
+
const isCustom = container?.getAttribute('data-custom-aspect-ratio') === 'true'
|
|
1039
1039
|
videoForm.value = {
|
|
1040
1040
|
src: container?.getAttribute('data-video-src') || '',
|
|
1041
1041
|
width: container?.getAttribute('data-width') || '',
|
|
1042
|
-
autoplay:
|
|
1043
|
-
mute:
|
|
1044
|
-
controls:
|
|
1045
|
-
loop:
|
|
1042
|
+
autoplay: container?.getAttribute('data-autoplay') === 'true',
|
|
1043
|
+
mute: container?.getAttribute('data-mute') === 'true',
|
|
1044
|
+
controls: container?.getAttribute('data-controls') === 'true',
|
|
1045
|
+
loop: container?.getAttribute('data-loop') === 'true',
|
|
1046
1046
|
aspectRatio: isCustom ? 'custom' : (container?.getAttribute('data-aspect-ratio') || '16:9'),
|
|
1047
1047
|
customWidth: container?.getAttribute('data-custom-width') || '',
|
|
1048
1048
|
customHeight: container?.getAttribute('data-custom-height') || '',
|
|
@@ -1071,7 +1071,7 @@ function openVideoModal(existingVideo: HTMLElement | null = null) {
|
|
|
1071
1071
|
|
|
1072
1072
|
// Function to validate video URL
|
|
1073
1073
|
function isValidVideoUrl(url: string): boolean {
|
|
1074
|
-
if (!url ||
|
|
1074
|
+
if (!url || url.trim() === '') { return false }
|
|
1075
1075
|
|
|
1076
1076
|
try {
|
|
1077
1077
|
// Check for iframe tags
|
|
@@ -1106,23 +1106,23 @@ function isValidVideoUrl(url: string): boolean {
|
|
|
1106
1106
|
}
|
|
1107
1107
|
}
|
|
1108
1108
|
function submitVideo() {
|
|
1109
|
-
if (!videoForm.value.src || !pendingVideoData) {return}
|
|
1109
|
+
if (!videoForm.value.src || !pendingVideoData) { return }
|
|
1110
1110
|
|
|
1111
1111
|
const { doc } = editor.state
|
|
1112
|
-
if (!doc) {return}
|
|
1112
|
+
if (!doc) { return }
|
|
1113
1113
|
|
|
1114
1114
|
const { existingVideo } = pendingVideoData
|
|
1115
1115
|
|
|
1116
1116
|
// Calculate aspect ratio
|
|
1117
1117
|
let { aspectRatio } = videoForm.value
|
|
1118
|
-
const isCustom =
|
|
1118
|
+
const isCustom = videoForm.value.aspectRatio === 'custom'
|
|
1119
1119
|
if (isCustom && videoForm.value.customWidth && videoForm.value.customHeight) {
|
|
1120
1120
|
aspectRatio = `${videoForm.value.customWidth}:${videoForm.value.customHeight}`
|
|
1121
1121
|
}
|
|
1122
1122
|
|
|
1123
1123
|
// Auto-adjust aspect ratio for YouTube Shorts
|
|
1124
1124
|
const isYoutubeShort = videoForm.value.src.includes('youtube.com/shorts/')
|
|
1125
|
-
if (isYoutubeShort && '16:9'
|
|
1125
|
+
if (isYoutubeShort && aspectRatio === '16:9') {
|
|
1126
1126
|
aspectRatio = '9:16'
|
|
1127
1127
|
}
|
|
1128
1128
|
|
|
@@ -1170,8 +1170,8 @@ function submitVideo() {
|
|
|
1170
1170
|
const description = doc.createElement('div')
|
|
1171
1171
|
description.className = 'video-placeholder-description'
|
|
1172
1172
|
let platformText = 'video'
|
|
1173
|
-
if (isYoutube) {platformText = 'YouTube video'}
|
|
1174
|
-
else if (isVimeo) {platformText = 'Vimeo video'}
|
|
1173
|
+
if (isYoutube) { platformText = 'YouTube video' }
|
|
1174
|
+
else if (isVimeo) { platformText = 'Vimeo video' }
|
|
1175
1175
|
description.textContent = platformText
|
|
1176
1176
|
|
|
1177
1177
|
// Try to get YouTube thumbnail if possible
|
|
@@ -1260,7 +1260,7 @@ function submitVideo() {
|
|
|
1260
1260
|
|
|
1261
1261
|
// Function to delete video
|
|
1262
1262
|
function deleteVideo() {
|
|
1263
|
-
if (!pendingVideoData?.existingVideo) {return}
|
|
1263
|
+
if (!pendingVideoData?.existingVideo) { return }
|
|
1264
1264
|
|
|
1265
1265
|
const { existingVideo } = pendingVideoData
|
|
1266
1266
|
existingVideo.remove()
|
|
@@ -1279,9 +1279,9 @@ function detectTableAlignment(table: HTMLTableElement): 'left' | 'center' | 'rig
|
|
|
1279
1279
|
|
|
1280
1280
|
console.log('Table margins:', { marginLeft, marginRight })
|
|
1281
1281
|
|
|
1282
|
-
if ('auto'
|
|
1282
|
+
if (marginLeft === 'auto' && marginRight === 'auto') {
|
|
1283
1283
|
return 'center'
|
|
1284
|
-
}if (marginLeft === 'auto' && marginRight === '0') {
|
|
1284
|
+
} if (marginLeft === 'auto' && marginRight === '0') {
|
|
1285
1285
|
return 'right'
|
|
1286
1286
|
} else {
|
|
1287
1287
|
return 'left'
|
|
@@ -1290,12 +1290,12 @@ function detectTableAlignment(table: HTMLTableElement): 'left' | 'center' | 'rig
|
|
|
1290
1290
|
|
|
1291
1291
|
function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
1292
1292
|
const { doc } = editor.state
|
|
1293
|
-
if (!doc) {return}
|
|
1293
|
+
if (!doc) { return }
|
|
1294
1294
|
|
|
1295
1295
|
// Get current selection for new tables
|
|
1296
1296
|
if (!existingTable) {
|
|
1297
1297
|
const selection = doc.getSelection()
|
|
1298
|
-
if (!selection || !selection.rangeCount) {return}
|
|
1298
|
+
if (!selection || !selection.rangeCount) { return }
|
|
1299
1299
|
const range = selection.getRangeAt(0)
|
|
1300
1300
|
pendingTableData = { selection, range, existingTable: null }
|
|
1301
1301
|
} else {
|
|
@@ -1317,11 +1317,11 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1317
1317
|
let alternateRowBg = '#f9f9f9'
|
|
1318
1318
|
let alternateRowTextColor = '#333333'
|
|
1319
1319
|
|
|
1320
|
-
if (tbody &&
|
|
1320
|
+
if (tbody && tbody.rows.length >= 2) {
|
|
1321
1321
|
const firstRow = tbody.rows[0]
|
|
1322
1322
|
const secondRow = tbody.rows[1]
|
|
1323
1323
|
|
|
1324
|
-
if (
|
|
1324
|
+
if (firstRow.cells.length > 0 && secondRow.cells.length > 0) {
|
|
1325
1325
|
const firstCell = firstRow.cells[0] as HTMLElement
|
|
1326
1326
|
const secondCell = secondRow.cells[0] as HTMLElement
|
|
1327
1327
|
|
|
@@ -1339,7 +1339,7 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1339
1339
|
|
|
1340
1340
|
tableForm.value = {
|
|
1341
1341
|
rows: tbody ? tbody.rows.length : 3,
|
|
1342
|
-
cols: tbody &&
|
|
1342
|
+
cols: tbody && tbody.rows.length > 0 ? tbody.rows[0].cells.length : 3,
|
|
1343
1343
|
width: Number.parseInt(existingTable.style.width) || 100,
|
|
1344
1344
|
borderWidth: Number.parseInt(existingTable.style.borderWidth) || 1,
|
|
1345
1345
|
borderColor: existingTable.style.borderColor || '#dddddd',
|
|
@@ -1352,7 +1352,7 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1352
1352
|
alternateRows: hasAlternatingRows,
|
|
1353
1353
|
alternateRowBgColor: alternateRowBg,
|
|
1354
1354
|
alternateRowTextColor,
|
|
1355
|
-
fixedLayout:
|
|
1355
|
+
fixedLayout: existingTable.style.tableLayout === 'fixed' || true, // ברירת מחדל true
|
|
1356
1356
|
alignment: detectTableAlignment(existingTable),
|
|
1357
1357
|
direction: existingTable.dir || 'ltr'
|
|
1358
1358
|
}
|
|
@@ -1382,10 +1382,10 @@ function openTableEditor(existingTable: HTMLTableElement | null = null) {
|
|
|
1382
1382
|
|
|
1383
1383
|
// Function to submit table changes
|
|
1384
1384
|
function submitTable() {
|
|
1385
|
-
if (!pendingTableData) {return}
|
|
1385
|
+
if (!pendingTableData) { return }
|
|
1386
1386
|
|
|
1387
1387
|
const { doc } = editor.state
|
|
1388
|
-
if (!doc) {return}
|
|
1388
|
+
if (!doc) { return }
|
|
1389
1389
|
|
|
1390
1390
|
if (pendingTableData.existingTable) {
|
|
1391
1391
|
// Update existing table instead of creating new one
|
|
@@ -1445,7 +1445,7 @@ function submitTable() {
|
|
|
1445
1445
|
const cells = row.querySelectorAll('td')
|
|
1446
1446
|
cells.forEach((cell) => {
|
|
1447
1447
|
const cellEl = cell as HTMLElement
|
|
1448
|
-
if (tableForm.value.alternateRows &&
|
|
1448
|
+
if (tableForm.value.alternateRows && i % 2 === 1) {
|
|
1449
1449
|
// Alternate rows: use special colors
|
|
1450
1450
|
cellEl.style.backgroundColor = tableForm.value.alternateRowBgColor
|
|
1451
1451
|
cellEl.style.color = tableForm.value.alternateRowTextColor
|
|
@@ -1470,7 +1470,7 @@ function submitTable() {
|
|
|
1470
1470
|
|
|
1471
1471
|
// Function to create new table (moved from submitTable)
|
|
1472
1472
|
function createNewTable(doc: Document) {
|
|
1473
|
-
if (!pendingTableData) {return}
|
|
1473
|
+
if (!pendingTableData) { return }
|
|
1474
1474
|
|
|
1475
1475
|
// Create new table with current settings
|
|
1476
1476
|
const table = doc.createElement('table')
|
|
@@ -1490,10 +1490,10 @@ function createNewTable(doc: Document) {
|
|
|
1490
1490
|
// Don't set textAlign on table - let it inherit from document direction
|
|
1491
1491
|
// table.style.textAlign = tableForm.value.alignment
|
|
1492
1492
|
|
|
1493
|
-
if (
|
|
1493
|
+
if (tableForm.value.alignment === 'center') {
|
|
1494
1494
|
table.style.marginLeft = 'auto'
|
|
1495
1495
|
table.style.marginRight = 'auto'
|
|
1496
|
-
} else if (
|
|
1496
|
+
} else if (tableForm.value.alignment === 'right') {
|
|
1497
1497
|
table.style.marginLeft = 'auto'
|
|
1498
1498
|
table.style.marginRight = '0'
|
|
1499
1499
|
} else {
|
|
@@ -1546,7 +1546,7 @@ function createNewTable(doc: Document) {
|
|
|
1546
1546
|
}
|
|
1547
1547
|
|
|
1548
1548
|
// Apply background and text colors
|
|
1549
|
-
if (tableForm.value.alternateRows &&
|
|
1549
|
+
if (tableForm.value.alternateRows && i % 2 === 1) {
|
|
1550
1550
|
// Alternate rows: use special colors
|
|
1551
1551
|
cell.style.backgroundColor = tableForm.value.alternateRowBgColor
|
|
1552
1552
|
cell.style.color = tableForm.value.alternateRowTextColor
|
|
@@ -1590,7 +1590,7 @@ function createNewTable(doc: Document) {
|
|
|
1590
1590
|
|
|
1591
1591
|
// Function to delete table
|
|
1592
1592
|
function deleteTable() {
|
|
1593
|
-
if (!pendingTableData?.existingTable) {return}
|
|
1593
|
+
if (!pendingTableData?.existingTable) { return }
|
|
1594
1594
|
|
|
1595
1595
|
const { existingTable } = pendingTableData
|
|
1596
1596
|
existingTable.remove()
|
|
@@ -1619,7 +1619,7 @@ function applyDefaultTableSettings(table: HTMLTableElement) {
|
|
|
1619
1619
|
const headers = table.querySelectorAll('th')
|
|
1620
1620
|
const cells = table.querySelectorAll('td')
|
|
1621
1621
|
|
|
1622
|
-
if (
|
|
1622
|
+
if (headers.length > 0) {
|
|
1623
1623
|
const colWidth = `${100 / headers.length}%`
|
|
1624
1624
|
headers.forEach((th) => {
|
|
1625
1625
|
if (!(th as HTMLElement).style.width) {
|
|
@@ -1628,7 +1628,7 @@ function applyDefaultTableSettings(table: HTMLTableElement) {
|
|
|
1628
1628
|
})
|
|
1629
1629
|
}
|
|
1630
1630
|
|
|
1631
|
-
if (
|
|
1631
|
+
if (cells.length > 0 && headers.length === 0) {
|
|
1632
1632
|
// If no headers, use first row to determine column count
|
|
1633
1633
|
const firstRow = table.querySelector('tr')
|
|
1634
1634
|
if (firstRow) {
|
|
@@ -1658,7 +1658,7 @@ function applyDefaultTableSettings(table: HTMLTableElement) {
|
|
|
1658
1658
|
|
|
1659
1659
|
// Function to delete image
|
|
1660
1660
|
function deleteImage() {
|
|
1661
|
-
if (!pendingImageData?.existingImage) {return}
|
|
1661
|
+
if (!pendingImageData?.existingImage) { return }
|
|
1662
1662
|
|
|
1663
1663
|
const { existingImage } = pendingImageData
|
|
1664
1664
|
existingImage.remove()
|
|
@@ -1670,7 +1670,7 @@ function deleteImage() {
|
|
|
1670
1670
|
|
|
1671
1671
|
// Function to delete embed
|
|
1672
1672
|
function deleteEmbed() {
|
|
1673
|
-
if (!pendingEmbedData?.existingEmbed) {return}
|
|
1673
|
+
if (!pendingEmbedData?.existingEmbed) { return }
|
|
1674
1674
|
|
|
1675
1675
|
const { existingEmbed } = pendingEmbedData
|
|
1676
1676
|
existingEmbed.remove()
|
|
@@ -1693,19 +1693,19 @@ function deleteEmbed() {
|
|
|
1693
1693
|
// Table manipulation functions
|
|
1694
1694
|
function mergeCellRight() {
|
|
1695
1695
|
const { doc } = editor.state
|
|
1696
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1696
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1697
1697
|
|
|
1698
1698
|
const cell = contextMenuCell.value
|
|
1699
1699
|
const row = cell.parentElement as HTMLTableRowElement
|
|
1700
1700
|
const cellIndex = Array.from(row.cells).indexOf(cell)
|
|
1701
1701
|
const table = cell.closest('table') as HTMLTableElement
|
|
1702
|
-
const isRTL = 'rtl'
|
|
1702
|
+
const isRTL = table?.dir === 'rtl'
|
|
1703
1703
|
|
|
1704
1704
|
// In RTL, "right" means the previous cell, in LTR it means the next cell
|
|
1705
1705
|
const targetIndex = isRTL ? cellIndex - 1 : cellIndex + 1
|
|
1706
1706
|
const targetCell = row.cells[targetIndex]
|
|
1707
1707
|
|
|
1708
|
-
if (targetCell &&
|
|
1708
|
+
if (targetCell && targetIndex >= 0 && targetIndex < row.cells.length) {
|
|
1709
1709
|
// Combine content
|
|
1710
1710
|
if (targetCell.innerHTML.trim()) {
|
|
1711
1711
|
cell.innerHTML += ` ${targetCell.innerHTML}`
|
|
@@ -1725,7 +1725,7 @@ function mergeCellRight() {
|
|
|
1725
1725
|
|
|
1726
1726
|
function mergeCellDown() {
|
|
1727
1727
|
const { doc } = editor.state
|
|
1728
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1728
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1729
1729
|
|
|
1730
1730
|
const cell = contextMenuCell.value
|
|
1731
1731
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1761,15 +1761,15 @@ function mergeCellDown() {
|
|
|
1761
1761
|
|
|
1762
1762
|
function splitCell() {
|
|
1763
1763
|
const { doc } = editor.state
|
|
1764
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1764
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1765
1765
|
|
|
1766
1766
|
const cell = contextMenuCell.value
|
|
1767
1767
|
const table = cell.closest('table') as HTMLTableElement
|
|
1768
|
-
const isRTL = 'rtl'
|
|
1768
|
+
const isRTL = table?.dir === 'rtl'
|
|
1769
1769
|
const colspan = Number.parseInt(cell.getAttribute('colspan') || '1')
|
|
1770
1770
|
const rowspan = Number.parseInt(cell.getAttribute('rowspan') || '1')
|
|
1771
1771
|
|
|
1772
|
-
if (
|
|
1772
|
+
if (colspan > 1) {
|
|
1773
1773
|
// Split horizontally
|
|
1774
1774
|
cell.setAttribute('colspan', '1')
|
|
1775
1775
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1790,7 +1790,7 @@ function splitCell() {
|
|
|
1790
1790
|
}
|
|
1791
1791
|
}
|
|
1792
1792
|
}
|
|
1793
|
-
} else if (
|
|
1793
|
+
} else if (rowspan > 1) {
|
|
1794
1794
|
// Split vertically
|
|
1795
1795
|
cell.setAttribute('rowspan', '1')
|
|
1796
1796
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1822,7 +1822,7 @@ function splitCell() {
|
|
|
1822
1822
|
|
|
1823
1823
|
function insertRowAbove() {
|
|
1824
1824
|
const { doc } = editor.state
|
|
1825
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1825
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1826
1826
|
|
|
1827
1827
|
const cell = contextMenuCell.value
|
|
1828
1828
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1849,7 +1849,7 @@ function insertRowAbove() {
|
|
|
1849
1849
|
|
|
1850
1850
|
function insertRowBelow() {
|
|
1851
1851
|
const { doc } = editor.state
|
|
1852
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1852
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1853
1853
|
|
|
1854
1854
|
const cell = contextMenuCell.value
|
|
1855
1855
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1876,7 +1876,7 @@ function insertRowBelow() {
|
|
|
1876
1876
|
|
|
1877
1877
|
function deleteRow() {
|
|
1878
1878
|
const { doc } = editor.state
|
|
1879
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1879
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1880
1880
|
|
|
1881
1881
|
const cell = contextMenuCell.value
|
|
1882
1882
|
const row = cell.parentElement as HTMLTableRowElement
|
|
@@ -1886,7 +1886,7 @@ function deleteRow() {
|
|
|
1886
1886
|
const tbody = table.querySelector('tbody') || table
|
|
1887
1887
|
const rows = tbody.querySelectorAll('tr')
|
|
1888
1888
|
|
|
1889
|
-
if (
|
|
1889
|
+
if (rows.length <= 1) {
|
|
1890
1890
|
alert('Cannot delete the last row')
|
|
1891
1891
|
return
|
|
1892
1892
|
}
|
|
@@ -1897,7 +1897,7 @@ function deleteRow() {
|
|
|
1897
1897
|
|
|
1898
1898
|
function insertColumnLeft() {
|
|
1899
1899
|
const { doc } = editor.state
|
|
1900
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1900
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1901
1901
|
|
|
1902
1902
|
const cell = contextMenuCell.value
|
|
1903
1903
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1906,7 +1906,7 @@ function insertColumnLeft() {
|
|
|
1906
1906
|
// Add new cell to each row at the same index
|
|
1907
1907
|
const rows = table.querySelectorAll('tr')
|
|
1908
1908
|
rows.forEach((row) => {
|
|
1909
|
-
const newCell = doc.createElement(
|
|
1909
|
+
const newCell = doc.createElement(row.parentElement?.tagName === 'THEAD' ? 'th' : 'td')
|
|
1910
1910
|
newCell.innerHTML = ' '
|
|
1911
1911
|
newCell.style.padding = '8px'
|
|
1912
1912
|
newCell.style.border = '1px solid #ddd'
|
|
@@ -1923,7 +1923,7 @@ function insertColumnLeft() {
|
|
|
1923
1923
|
|
|
1924
1924
|
function insertColumnRight() {
|
|
1925
1925
|
const { doc } = editor.state
|
|
1926
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1926
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1927
1927
|
|
|
1928
1928
|
const cell = contextMenuCell.value
|
|
1929
1929
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1932,7 +1932,7 @@ function insertColumnRight() {
|
|
|
1932
1932
|
// Add new cell to each row after the current index
|
|
1933
1933
|
const rows = table.querySelectorAll('tr')
|
|
1934
1934
|
rows.forEach((row) => {
|
|
1935
|
-
const newCell = doc.createElement(
|
|
1935
|
+
const newCell = doc.createElement(row.parentElement?.tagName === 'THEAD' ? 'th' : 'td')
|
|
1936
1936
|
newCell.innerHTML = ' '
|
|
1937
1937
|
newCell.style.padding = '8px'
|
|
1938
1938
|
newCell.style.border = '1px solid #ddd'
|
|
@@ -1950,7 +1950,7 @@ function insertColumnRight() {
|
|
|
1950
1950
|
|
|
1951
1951
|
function deleteColumn() {
|
|
1952
1952
|
const { doc } = editor.state
|
|
1953
|
-
if (!doc || !contextMenuCell.value) {return}
|
|
1953
|
+
if (!doc || !contextMenuCell.value) { return }
|
|
1954
1954
|
|
|
1955
1955
|
const cell = contextMenuCell.value
|
|
1956
1956
|
const table = cell.closest('table') as HTMLTableElement
|
|
@@ -1958,7 +1958,7 @@ function deleteColumn() {
|
|
|
1958
1958
|
|
|
1959
1959
|
// Check if this is the only column
|
|
1960
1960
|
const firstRow = table.querySelector('tr')
|
|
1961
|
-
if (firstRow &&
|
|
1961
|
+
if (firstRow && firstRow.cells.length <= 1) {
|
|
1962
1962
|
alert('Cannot delete the last column')
|
|
1963
1963
|
return
|
|
1964
1964
|
}
|
|
@@ -1976,18 +1976,18 @@ function deleteColumn() {
|
|
|
1976
1976
|
|
|
1977
1977
|
// Table context menu functions
|
|
1978
1978
|
const canMergeRight = computed(() => {
|
|
1979
|
-
if (!contextMenuCell.value) {return false}
|
|
1979
|
+
if (!contextMenuCell.value) { return false }
|
|
1980
1980
|
const cell = contextMenuCell.value
|
|
1981
1981
|
const row = cell.parentElement as HTMLTableRowElement
|
|
1982
1982
|
const cellIndex = Array.from(row.cells).indexOf(cell)
|
|
1983
1983
|
const table = cell.closest('table') as HTMLTableElement
|
|
1984
|
-
const isRTL = 'rtl'
|
|
1984
|
+
const isRTL = table?.dir === 'rtl'
|
|
1985
1985
|
const targetIndex = isRTL ? cellIndex - 1 : cellIndex + 1
|
|
1986
|
-
return
|
|
1986
|
+
return targetIndex >= 0 && targetIndex < row.cells.length
|
|
1987
1987
|
})
|
|
1988
1988
|
|
|
1989
1989
|
const canMergeDown = computed(() => {
|
|
1990
|
-
if (!contextMenuCell.value) {return false}
|
|
1990
|
+
if (!contextMenuCell.value) { return false }
|
|
1991
1991
|
const cell = contextMenuCell.value
|
|
1992
1992
|
const table = cell.closest('table') as HTMLTableElement
|
|
1993
1993
|
const rows = Array.from(table.rows)
|
|
@@ -1997,11 +1997,11 @@ const canMergeDown = computed(() => {
|
|
|
1997
1997
|
})
|
|
1998
1998
|
|
|
1999
1999
|
const canSplit = computed(() => {
|
|
2000
|
-
if (!contextMenuCell.value) {return false}
|
|
2000
|
+
if (!contextMenuCell.value) { return false }
|
|
2001
2001
|
const cell = contextMenuCell.value
|
|
2002
2002
|
const colspan = Number.parseInt(cell.getAttribute('colspan') || '1')
|
|
2003
2003
|
const rowspan = Number.parseInt(cell.getAttribute('rowspan') || '1')
|
|
2004
|
-
return
|
|
2004
|
+
return colspan > 1 || rowspan > 1
|
|
2005
2005
|
})
|
|
2006
2006
|
|
|
2007
2007
|
function handleTableContextMenu(event: MouseEvent) {
|
|
@@ -2028,14 +2028,14 @@ function handleTableContextMenu(event: MouseEvent) {
|
|
|
2028
2028
|
// }
|
|
2029
2029
|
|
|
2030
2030
|
// Expose debug methods if debug mode is enabled
|
|
2031
|
-
const debugMethods =
|
|
2032
|
-
const hasRTL =
|
|
2031
|
+
const debugMethods = computed(() => editor.state.debug)
|
|
2032
|
+
const hasRTL = computed(() => /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(props.modelValue))
|
|
2033
2033
|
|
|
2034
2034
|
// Computed property to handle height prop
|
|
2035
|
-
const editorHeight =
|
|
2036
|
-
if (
|
|
2035
|
+
const editorHeight = computed(() => {
|
|
2036
|
+
if (typeof props.height === 'number') {
|
|
2037
2037
|
return `${props.height}px`
|
|
2038
|
-
}if (typeof props.height === 'string') {
|
|
2038
|
+
} if (typeof props.height === 'string') {
|
|
2039
2039
|
return props.height
|
|
2040
2040
|
}
|
|
2041
2041
|
return '240px' // default height
|
|
@@ -2103,16 +2103,16 @@ function setupTableEditButtons(doc: Document) {
|
|
|
2103
2103
|
if (table.style.marginLeft && table.style.marginRight) {
|
|
2104
2104
|
// Detect current alignment
|
|
2105
2105
|
let alignment = 'left'
|
|
2106
|
-
if (
|
|
2106
|
+
if (table.style.marginLeft === 'auto' && table.style.marginRight === 'auto') {
|
|
2107
2107
|
alignment = 'center'
|
|
2108
|
-
} else if (
|
|
2108
|
+
} else if (table.style.marginLeft === 'auto') {
|
|
2109
2109
|
alignment = 'right'
|
|
2110
2110
|
}
|
|
2111
2111
|
|
|
2112
2112
|
// Apply flex alignment to wrapper
|
|
2113
|
-
if ('center'
|
|
2113
|
+
if (alignment === 'center') {
|
|
2114
2114
|
wrapper.style.alignItems = 'center'
|
|
2115
|
-
} else if ('right'
|
|
2115
|
+
} else if (alignment === 'right') {
|
|
2116
2116
|
wrapper.style.alignItems = 'flex-end'
|
|
2117
2117
|
} else {
|
|
2118
2118
|
wrapper.style.alignItems = 'flex-start'
|
|
@@ -2190,14 +2190,14 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2190
2190
|
}
|
|
2191
2191
|
|
|
2192
2192
|
// If body is completely empty, add a paragraph and return
|
|
2193
|
-
if (!doc.body.innerHTML.trim() ||
|
|
2193
|
+
if (!doc.body.innerHTML.trim() || doc.body.innerHTML === '') {
|
|
2194
2194
|
const direction = getCurrentDirection()
|
|
2195
2195
|
doc.body.innerHTML = `<p dir="${direction}"><br></p>`
|
|
2196
2196
|
return
|
|
2197
2197
|
}
|
|
2198
2198
|
|
|
2199
2199
|
// Mark body as being normalized to prevent recursive processing
|
|
2200
|
-
if (
|
|
2200
|
+
if (doc.body.dataset.normalizing === 'true') {
|
|
2201
2201
|
return
|
|
2202
2202
|
}
|
|
2203
2203
|
doc.body.dataset.normalizing = 'true'
|
|
@@ -2213,7 +2213,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2213
2213
|
const parent = node.parentNode as HTMLElement
|
|
2214
2214
|
return (parent === doc.body
|
|
2215
2215
|
&& node.textContent?.trim()
|
|
2216
|
-
&&
|
|
2216
|
+
&& node.textContent.trim().length > 0)
|
|
2217
2217
|
? NodeFilter.FILTER_ACCEPT
|
|
2218
2218
|
: NodeFilter.FILTER_REJECT
|
|
2219
2219
|
}
|
|
@@ -2262,13 +2262,13 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2262
2262
|
const paras = Array.from(doc.body.querySelectorAll('p'))
|
|
2263
2263
|
for (let i = 0; i < paras.length; i++) {
|
|
2264
2264
|
const current = paras[i]
|
|
2265
|
-
const isEmpty = !current.textContent?.trim() || '<br>'
|
|
2265
|
+
const isEmpty = !current.textContent?.trim() || current.innerHTML === '<br>'
|
|
2266
2266
|
|
|
2267
2267
|
if (isEmpty) {
|
|
2268
2268
|
// Only remove if we have consecutive empty paragraphs at the end
|
|
2269
2269
|
const isLastPara = i === paras.length - 1
|
|
2270
|
-
const prevPara =
|
|
2271
|
-
const isPrevEmpty = prevPara && (!prevPara.textContent?.trim() || '<br>'
|
|
2270
|
+
const prevPara = i > 0 ? paras[i - 1] : null
|
|
2271
|
+
const isPrevEmpty = prevPara && (!prevPara.textContent?.trim() || prevPara.innerHTML === '<br>')
|
|
2272
2272
|
|
|
2273
2273
|
// Keep at least one empty paragraph for cursor placement
|
|
2274
2274
|
if (isPrevEmpty && !isLastPara) {
|
|
@@ -2291,7 +2291,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2291
2291
|
detectAndSetDirection()
|
|
2292
2292
|
|
|
2293
2293
|
// Handle complete content deletion immediately
|
|
2294
|
-
if (!doc.body.innerHTML.trim() ||
|
|
2294
|
+
if (!doc.body.innerHTML.trim() || doc.body.innerHTML === '') {
|
|
2295
2295
|
if (props.placeholder) {
|
|
2296
2296
|
addPlaceholder()
|
|
2297
2297
|
} else {
|
|
@@ -2318,9 +2318,9 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2318
2318
|
|
|
2319
2319
|
// Handle Enter key
|
|
2320
2320
|
doc.addEventListener('keydown', (e) => {
|
|
2321
|
-
if ('Enter'
|
|
2321
|
+
if (e.key === 'Enter') {
|
|
2322
2322
|
const selection = doc.getSelection()
|
|
2323
|
-
if (!selection || !selection.rangeCount) {return}
|
|
2323
|
+
if (!selection || !selection.rangeCount) { return }
|
|
2324
2324
|
|
|
2325
2325
|
const range = selection.getRangeAt(0)
|
|
2326
2326
|
|
|
@@ -2346,13 +2346,13 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2346
2346
|
}
|
|
2347
2347
|
paragraph = (paragraph as Element).closest('p,h1,h2,h3,h4,h5,h6') as HTMLElement
|
|
2348
2348
|
|
|
2349
|
-
if (!paragraph) {return}
|
|
2349
|
+
if (!paragraph) { return }
|
|
2350
2350
|
|
|
2351
2351
|
// Check if current paragraph is empty and previous paragraph is also empty
|
|
2352
2352
|
const currentIsEmpty = !paragraph.textContent?.trim()
|
|
2353
2353
|
const prevSibling = (paragraph as Element).previousElementSibling as HTMLElement
|
|
2354
2354
|
const prevIsEmpty = prevSibling
|
|
2355
|
-
&& ('P'
|
|
2355
|
+
&& (prevSibling.tagName === 'P')
|
|
2356
2356
|
&& !prevSibling.textContent?.trim()
|
|
2357
2357
|
|
|
2358
2358
|
// If both current and previous paragraphs are empty, don't create another empty paragraph
|
|
@@ -2442,7 +2442,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2442
2442
|
}) // Add a MutationObserver to catch structural changes that might create loose text
|
|
2443
2443
|
const observer = new MutationObserver((mutations) => {
|
|
2444
2444
|
for (const mutation of mutations) {
|
|
2445
|
-
if ('childList'
|
|
2445
|
+
if (mutation.type === 'childList') {
|
|
2446
2446
|
// Check if any loose text nodes were added to body
|
|
2447
2447
|
Array.from(mutation.addedNodes).forEach((addedNode) => {
|
|
2448
2448
|
if (addedNode.nodeType === Node.TEXT_NODE
|
|
@@ -2458,7 +2458,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2458
2458
|
// Check if a table was added
|
|
2459
2459
|
else if (addedNode.nodeType === Node.ELEMENT_NODE) {
|
|
2460
2460
|
const element = addedNode as HTMLElement
|
|
2461
|
-
if ('TABLE'
|
|
2461
|
+
if (element.tagName === 'TABLE') {
|
|
2462
2462
|
console.log('MutationObserver detected new table:', element)
|
|
2463
2463
|
setTimeout(() => {
|
|
2464
2464
|
console.log('Applying default table settings...')
|
|
@@ -2476,7 +2476,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2476
2476
|
}
|
|
2477
2477
|
|
|
2478
2478
|
// Also apply direction to list items if it's a list
|
|
2479
|
-
if ('UL'
|
|
2479
|
+
if (element.tagName === 'UL' || element.tagName === 'OL') {
|
|
2480
2480
|
const listItems = element.querySelectorAll('li')
|
|
2481
2481
|
listItems.forEach((li) => {
|
|
2482
2482
|
if (!li.dir) {
|
|
@@ -2543,7 +2543,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2543
2543
|
|
|
2544
2544
|
// Get current selection
|
|
2545
2545
|
const selection = doc.getSelection()
|
|
2546
|
-
if (!selection) {return}
|
|
2546
|
+
if (!selection) { return }
|
|
2547
2547
|
|
|
2548
2548
|
// Create a range that selects the entire link
|
|
2549
2549
|
const range = doc.createRange()
|
|
@@ -2553,7 +2553,7 @@ function setupAutoWrapping(doc: Document) {
|
|
|
2553
2553
|
|
|
2554
2554
|
// Populate the form with existing link data
|
|
2555
2555
|
linkForm.value.url = link.href
|
|
2556
|
-
linkForm.value.openInNewTab = '_blank'
|
|
2556
|
+
linkForm.value.openInNewTab = link.target === '_blank'
|
|
2557
2557
|
|
|
2558
2558
|
// Store the link data for editing
|
|
2559
2559
|
pendingLinkData = {
|
|
@@ -2722,7 +2722,7 @@ async function initEditor() {
|
|
|
2722
2722
|
|
|
2723
2723
|
// Write the complete HTML document to the iframe
|
|
2724
2724
|
const doc = iframe.value.contentDocument || iframe.value.contentWindow?.document
|
|
2725
|
-
if (!doc) {return}
|
|
2725
|
+
if (!doc) { return }
|
|
2726
2726
|
|
|
2727
2727
|
// First write the content
|
|
2728
2728
|
doc.open()
|
|
@@ -2737,7 +2737,7 @@ async function initEditor() {
|
|
|
2737
2737
|
doc.body.contentEditable = 'true'
|
|
2738
2738
|
|
|
2739
2739
|
// Set default direction based on content
|
|
2740
|
-
doc.body.dir = hasRTL ? 'rtl' : 'ltr'
|
|
2740
|
+
doc.body.dir = hasRTL.value ? 'rtl' : 'ltr'
|
|
2741
2741
|
|
|
2742
2742
|
// Apply direction to existing blockquotes and lists
|
|
2743
2743
|
const blockElements = doc.body.querySelectorAll('blockquote, ul, ol')
|
|
@@ -2751,7 +2751,7 @@ async function initEditor() {
|
|
|
2751
2751
|
}
|
|
2752
2752
|
|
|
2753
2753
|
// Also apply direction to list items
|
|
2754
|
-
if ('UL'
|
|
2754
|
+
if (htmlElement.tagName === 'UL' || htmlElement.tagName === 'OL') {
|
|
2755
2755
|
const listItems = htmlElement.querySelectorAll('li')
|
|
2756
2756
|
listItems.forEach((li) => {
|
|
2757
2757
|
const listItem = li as HTMLElement
|
|
@@ -2775,7 +2775,7 @@ async function initEditor() {
|
|
|
2775
2775
|
// Clear all formatting by removing styles and replacing with plain text
|
|
2776
2776
|
const elements = doc.body.querySelectorAll('*')
|
|
2777
2777
|
elements.forEach((el) => {
|
|
2778
|
-
if ('P'
|
|
2778
|
+
if (el.tagName !== 'P' && el.tagName !== 'BR') {
|
|
2779
2779
|
const textContent = el.textContent || ''
|
|
2780
2780
|
if (textContent.trim()) {
|
|
2781
2781
|
const p = doc.createElement('p')
|
|
@@ -2784,10 +2784,10 @@ async function initEditor() {
|
|
|
2784
2784
|
} else {
|
|
2785
2785
|
el.remove()
|
|
2786
2786
|
}
|
|
2787
|
-
} else if ('P'
|
|
2787
|
+
} else if (el.tagName === 'P') {
|
|
2788
2788
|
// Remove all attributes from paragraphs
|
|
2789
2789
|
Array.from(el.attributes).forEach((attr) => {
|
|
2790
|
-
if ('dir'
|
|
2790
|
+
if (attr.name !== 'dir') {
|
|
2791
2791
|
el.removeAttribute(attr.name)
|
|
2792
2792
|
}
|
|
2793
2793
|
})
|
|
@@ -2811,7 +2811,7 @@ async function initEditor() {
|
|
|
2811
2811
|
doc.addEventListener('click', (e) => {
|
|
2812
2812
|
setTimeout(() => {
|
|
2813
2813
|
const selection = doc.getSelection()
|
|
2814
|
-
if (!selection ||
|
|
2814
|
+
if (!selection || selection.rangeCount === 0 || selection.getRangeAt(0).collapsed) {
|
|
2815
2815
|
hideInlineToolbar()
|
|
2816
2816
|
}
|
|
2817
2817
|
}, 10)
|
|
@@ -2822,7 +2822,7 @@ async function initEditor() {
|
|
|
2822
2822
|
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Escape'].includes(e.key)) {
|
|
2823
2823
|
setTimeout(() => {
|
|
2824
2824
|
const selection = doc.getSelection()
|
|
2825
|
-
if (!selection ||
|
|
2825
|
+
if (!selection || selection.rangeCount === 0 || selection.getRangeAt(0).collapsed) {
|
|
2826
2826
|
hideInlineToolbar()
|
|
2827
2827
|
}
|
|
2828
2828
|
}, 10)
|
|
@@ -2916,7 +2916,7 @@ async function initEditor() {
|
|
|
2916
2916
|
}
|
|
2917
2917
|
|
|
2918
2918
|
// Only focus if autofocus is explicitly set to true
|
|
2919
|
-
if (
|
|
2919
|
+
if (props.autofocus === true) {
|
|
2920
2920
|
doc.body.focus()
|
|
2921
2921
|
}
|
|
2922
2922
|
|
|
@@ -2942,7 +2942,7 @@ function updateIframeColors() {
|
|
|
2942
2942
|
hasInitialized: hasInitialized.value
|
|
2943
2943
|
})
|
|
2944
2944
|
|
|
2945
|
-
if (!iframe.value?.contentDocument ||
|
|
2945
|
+
if (!iframe.value?.contentDocument || iframe.value.contentDocument === null) {
|
|
2946
2946
|
console.warn('❌ No iframe or contentDocument')
|
|
2947
2947
|
return
|
|
2948
2948
|
}
|
|
@@ -2957,7 +2957,7 @@ function updateIframeColors() {
|
|
|
2957
2957
|
console.log('✅ Created new style element')
|
|
2958
2958
|
}
|
|
2959
2959
|
|
|
2960
|
-
const fontSize = props.fontSize ? (
|
|
2960
|
+
const fontSize = props.fontSize ? (typeof props.fontSize === 'number' ? `${props.fontSize}px` : props.fontSize) : '16px'
|
|
2961
2961
|
|
|
2962
2962
|
const css = `
|
|
2963
2963
|
:root {
|
|
@@ -3001,7 +3001,7 @@ watch([currentInputColor, currentTextColor], (newValues, oldValues) => {
|
|
|
3001
3001
|
watch(() => props.modelValue, (newValue, oldValue) => {
|
|
3002
3002
|
if (newValue !== editor.state.content) {
|
|
3003
3003
|
// Only reset if content change is significant (not just minor edits)
|
|
3004
|
-
if (!oldValue ||
|
|
3004
|
+
if (!oldValue || Math.abs(newValue.length - oldValue.length) > 50) {
|
|
3005
3005
|
hasInitialized.value = false
|
|
3006
3006
|
// For external changes, update content directly but then push to history
|
|
3007
3007
|
editor.state.content = newValue
|
|
@@ -3027,7 +3027,7 @@ watch(() => props.modelValue, (newValue, oldValue) => {
|
|
|
3027
3027
|
|
|
3028
3028
|
watch(() => editor.state.content, (newValue) => {
|
|
3029
3029
|
if (editor.state.doc?.body) {
|
|
3030
|
-
editor.state.doc.body.dir = hasRTL ? 'rtl' : 'ltr'
|
|
3030
|
+
editor.state.doc.body.dir = hasRTL.value ? 'rtl' : 'ltr'
|
|
3031
3031
|
}
|
|
3032
3032
|
emit('update:modelValue', newValue)
|
|
3033
3033
|
})
|
|
@@ -3036,10 +3036,10 @@ watch(() => editor.state.content, (newValue) => {
|
|
|
3036
3036
|
watch(() => tableForm.value.alignment, (newAlignment) => {
|
|
3037
3037
|
if (pendingTableData?.existingTable) {
|
|
3038
3038
|
const table = pendingTableData.existingTable
|
|
3039
|
-
if ('center'
|
|
3039
|
+
if (newAlignment === 'center') {
|
|
3040
3040
|
table.style.marginLeft = 'auto'
|
|
3041
3041
|
table.style.marginRight = 'auto'
|
|
3042
|
-
} else if ('right'
|
|
3042
|
+
} else if (newAlignment === 'right') {
|
|
3043
3043
|
table.style.marginLeft = 'auto'
|
|
3044
3044
|
table.style.marginRight = '0'
|
|
3045
3045
|
} else {
|
|
@@ -3060,13 +3060,13 @@ function handleGlobalClick() {
|
|
|
3060
3060
|
}
|
|
3061
3061
|
|
|
3062
3062
|
// Add event listener when component mounts
|
|
3063
|
-
if ('undefined'
|
|
3063
|
+
if (typeof window !== 'undefined') {
|
|
3064
3064
|
window.addEventListener('click', handleGlobalClick)
|
|
3065
3065
|
}
|
|
3066
3066
|
|
|
3067
3067
|
// Cleanup event listener
|
|
3068
3068
|
onBeforeUnmount(() => {
|
|
3069
|
-
if ('undefined'
|
|
3069
|
+
if (typeof window !== 'undefined') {
|
|
3070
3070
|
window.removeEventListener('click', handleGlobalClick)
|
|
3071
3071
|
}
|
|
3072
3072
|
})
|