@bagelink/vue 0.0.865 → 0.0.871
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Carousel.vue.d.ts.map +1 -1
- package/dist/components/MapEmbed.vue.d.ts +4 -3
- package/dist/components/MapEmbed.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText2/Toolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText2/formatting.d.ts +6 -0
- package/dist/components/form/inputs/RichText2/formatting.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText2/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText2/richtext-types.d.ts +1 -1
- package/dist/components/form/inputs/RichText2/richtext-types.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/index.d.ts +2 -2
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/components/layout/BottomMenu.vue.d.ts +1 -0
- package/dist/components/layout/BottomMenu.vue.d.ts.map +1 -1
- package/dist/index.cjs +159 -86
- package/dist/index.mjs +159 -86
- package/dist/style.css +32 -28
- package/package.json +1 -1
- package/src/components/Carousel.vue +5 -3
- package/src/components/MapEmbed.vue +41 -14
- package/src/components/form/inputs/RichText.zip +0 -0
- package/src/components/form/inputs/RichText2/Toolbar.vue +10 -15
- package/src/components/form/inputs/RichText2/formatting.ts +69 -25
- package/src/components/form/inputs/RichText2/index.vue +40 -33
- package/src/components/form/inputs/RichText2/richtext-types.ts +1 -0
- package/src/components/form/inputs/index.ts +2 -2
- package/src/components/layout/BottomMenu.vue +1 -0
package/package.json
CHANGED
|
@@ -40,9 +40,11 @@ function disableDrag() {
|
|
|
40
40
|
|
|
41
41
|
function updateHeight() {
|
|
42
42
|
if (!props.autoHeight || !bglSlider) return
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
setTimeout(() => {
|
|
44
|
+
const children = Array.from(bglSlider.children[activeSlideIndex].children)
|
|
45
|
+
const totalHeight = children.reduce((sum, el) => sum + el.clientHeight, 0)
|
|
46
|
+
yHeight = `${totalHeight}px`
|
|
47
|
+
}, 200)
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
function easeScroll(target: number, duration = 500) {
|
|
@@ -5,9 +5,10 @@ import { onMounted, watch } from 'vue'
|
|
|
5
5
|
import './leaflet/leaflet.css'
|
|
6
6
|
|
|
7
7
|
type MapMarker = {
|
|
8
|
-
lat: number
|
|
9
|
-
lon: number
|
|
10
|
-
|
|
8
|
+
lat: number | string
|
|
9
|
+
lon: number | string
|
|
10
|
+
label?: string
|
|
11
|
+
} | [(number | string), (number | string), string?]
|
|
11
12
|
|
|
12
13
|
const props = withDefaults(
|
|
13
14
|
defineProps<{
|
|
@@ -20,7 +21,7 @@ const props = withDefaults(
|
|
|
20
21
|
}>(),
|
|
21
22
|
{
|
|
22
23
|
center: () => [31.7683, 35.2137],
|
|
23
|
-
zoom:
|
|
24
|
+
zoom: 15,
|
|
24
25
|
height: 400,
|
|
25
26
|
zoomControl: true,
|
|
26
27
|
markerIcon: '',
|
|
@@ -32,7 +33,7 @@ let map = $ref<Map>()
|
|
|
32
33
|
const _markers = $ref<Marker[]>([])
|
|
33
34
|
const id = $ref(Math.random().toString(36).slice(2, 10))
|
|
34
35
|
|
|
35
|
-
const defaultMarkerSVG = '<svg
|
|
36
|
+
const defaultMarkerSVG = '<svg width="28" height="38" viewBox="0 0 28 38" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.2263 37.7955C17.0897 37.7955 19.4109 37.0138 19.4109 36.0496C19.4109 35.0854 17.0897 34.3037 14.2263 34.3037C11.363 34.3037 9.04175 35.0854 9.04175 36.0496C9.04175 37.0138 11.363 37.7955 14.2263 37.7955Z" fill="black" fill-opacity="0.1"/><path d="M14.2265 0.549591C21.2842 0.549591 27.0131 6.23786 27.0787 13.28V13.4024C27.0787 19.3328 24.4759 24.4306 21.5627 28.2764C18.6511 32.12 15.4577 34.6754 14.3457 35.5097C14.2748 35.5629 14.1778 35.5629 14.1068 35.5097C12.9947 34.675 9.80135 32.1197 6.88984 28.2762C3.97665 24.4304 1.37378 19.3328 1.37378 13.4024C1.37378 6.30387 7.12806 0.549591 14.2265 0.549591Z" fill="#ED1b3E" stroke="#ED6C6F"/><path d="M14.2263 21.6185C18.7639 21.6185 22.4424 17.94 22.4424 13.4024C22.4424 8.86477 18.7639 5.18631 14.2263 5.18631C9.68872 5.18631 6.01025 8.86477 6.01025 13.4024C6.01025 17.94 9.68872 21.6185 14.2263 21.6185Z" fill="white"/></svg>'
|
|
36
37
|
const leafletScriptUrl = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js'
|
|
37
38
|
|
|
38
39
|
async function loadGlobalL() {
|
|
@@ -53,20 +54,37 @@ async function initializeMap() {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
function addMarker(L: any, latlng: LatLngExpression) {
|
|
57
|
+
function addMarker(L: any, latlng: LatLngExpression, label?: string) {
|
|
57
58
|
const iconSVG = props.markerIcon || defaultMarkerSVG
|
|
58
59
|
const customIcon = L?.icon({
|
|
59
60
|
iconUrl: `data:image/svg+xml;utf8,${encodeURIComponent(iconSVG)}`,
|
|
60
61
|
iconSize: [32, 32],
|
|
61
62
|
})
|
|
62
|
-
|
|
63
63
|
const marker = L?.marker(latlng, { icon: customIcon }).addTo(map as Map)
|
|
64
|
+
|
|
65
|
+
if (label) {
|
|
66
|
+
marker.bindTooltip(label, { direction: 'top' }) // Use `bindPopup` if you want a click-to-show label
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
marker.on('click', () => {
|
|
70
|
+
console.log('Marker clicked:', latlng)
|
|
71
|
+
marker.openPopup()
|
|
72
|
+
})
|
|
73
|
+
|
|
64
74
|
_markers.push(marker)
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
function fitMarkers(L: any) {
|
|
68
78
|
if (_markers.length > 0) {
|
|
69
|
-
map
|
|
79
|
+
const latLngs = _markers.map(marker => marker.getLatLng())
|
|
80
|
+
const bounds = L.latLngBounds(latLngs)
|
|
81
|
+
console.log(props.zoom, bounds.getCenter())
|
|
82
|
+
map?.setView(bounds.getCenter(), props.zoom) // A
|
|
83
|
+
map?.fitBounds(bounds, {
|
|
84
|
+
animate: true,
|
|
85
|
+
maxZoom: props.zoom, // B
|
|
86
|
+
padding: [20, 20], // Adjust padding as needed
|
|
87
|
+
})
|
|
70
88
|
}
|
|
71
89
|
}
|
|
72
90
|
|
|
@@ -74,12 +92,16 @@ async function watchMarkers(markers?: MapMarker[]) {
|
|
|
74
92
|
if (!L) L = await loadGlobalL()
|
|
75
93
|
_markers.forEach(marker => marker.remove())
|
|
76
94
|
if (!markers) return
|
|
95
|
+
|
|
77
96
|
for (const marker of markers) {
|
|
78
|
-
const [lat, lon] = Array.isArray(marker)
|
|
97
|
+
const [lat, lon, label] = Array.isArray(marker)
|
|
98
|
+
? [marker[0], marker[1], marker[2] as string]
|
|
99
|
+
: [marker.lat, marker.lon, marker.label]
|
|
100
|
+
|
|
79
101
|
if (!map) initializeMap()
|
|
80
|
-
addMarker(L, [lat, lon])
|
|
81
|
-
fitMarkers(L)
|
|
102
|
+
addMarker(L, [+lat, +lon], label)
|
|
82
103
|
}
|
|
104
|
+
fitMarkers(L)
|
|
83
105
|
}
|
|
84
106
|
|
|
85
107
|
watch(() => props.markers, watchMarkers, { immediate: true })
|
|
@@ -89,7 +111,7 @@ onMounted(initializeMap)
|
|
|
89
111
|
</script>
|
|
90
112
|
|
|
91
113
|
<template>
|
|
92
|
-
<div :id="id" class="leaflet-map" :style="{ height: `${props.height || 400}px` }" />
|
|
114
|
+
<div :id="id" class="leaflet-map" :style="{ height: `${props.height || 400}px` }" dir="ltr" />
|
|
93
115
|
</template>
|
|
94
116
|
|
|
95
117
|
<style>
|
|
@@ -97,7 +119,8 @@ onMounted(initializeMap)
|
|
|
97
119
|
height: 100%;
|
|
98
120
|
border-radius: var(--input-border-radius);
|
|
99
121
|
position: relative;
|
|
100
|
-
background: var(--bgl-bg)
|
|
122
|
+
background: var(--bgl-bg);
|
|
123
|
+
direction: ltr;
|
|
101
124
|
}
|
|
102
125
|
|
|
103
126
|
.leaflet-map::after {
|
|
@@ -117,7 +140,7 @@ onMounted(initializeMap)
|
|
|
117
140
|
}
|
|
118
141
|
|
|
119
142
|
.leaflet-pane.leaflet-marker-pane img {
|
|
120
|
-
filter: drop-shadow(0px 8px 3px rgba(0, 0, 0, 0.2));
|
|
143
|
+
/* filter: drop-shadow(0px 8px 3px rgba(0, 0, 0, 0.2)); */
|
|
121
144
|
}
|
|
122
145
|
|
|
123
146
|
.leaflet-touch .leaflet-control-zoom-in,
|
|
@@ -160,4 +183,8 @@ onMounted(initializeMap)
|
|
|
160
183
|
.leaflet-bar a:focus {
|
|
161
184
|
filter: var(--bgl-active-filter);
|
|
162
185
|
}
|
|
186
|
+
|
|
187
|
+
.leaflet-marker-icon {
|
|
188
|
+
cursor: pointer;
|
|
189
|
+
}
|
|
163
190
|
</style>
|
|
Binary file
|
|
@@ -16,6 +16,11 @@ interface toolbarOption {
|
|
|
16
16
|
class?: string
|
|
17
17
|
}
|
|
18
18
|
const toolbarOptions: toolbarOption[] = [
|
|
19
|
+
{ name: 'formatBlock', label: 'h2', icon: 'format_h2' },
|
|
20
|
+
{ name: 'formatBlock', label: 'h3', icon: 'format_h3' },
|
|
21
|
+
{ name: 'formatBlock', label: 'h4', icon: 'format_h4' },
|
|
22
|
+
{ name: 'formatBlock', label: 'h5', icon: 'format_h5' },
|
|
23
|
+
{ name: 'formatBlock', label: 'h6', icon: 'format_h6' },
|
|
19
24
|
{ name: 'separator' },
|
|
20
25
|
{ name: 'bold', label: 'Bold', icon: 'format_bold' },
|
|
21
26
|
{ name: 'italic', label: 'Italic', icon: 'format_italic' },
|
|
@@ -46,34 +51,24 @@ const toolbarOptions: toolbarOption[] = [
|
|
|
46
51
|
// emit('action', 'fontSize', size)
|
|
47
52
|
// }
|
|
48
53
|
// }
|
|
49
|
-
function handleSelectChange(selectedOption: string) {
|
|
50
|
-
emit('action', 'formatBlock', selectedOption)
|
|
51
|
-
}
|
|
52
54
|
</script>
|
|
53
55
|
|
|
54
56
|
<template>
|
|
55
57
|
<div class="toolbar flex gap-025 pb-05 flex-wrap" role="toolbar">
|
|
56
|
-
<
|
|
57
|
-
class="m-0 w150"
|
|
58
|
-
:options="['Text', 'Heading 1', 'Heading 2', 'Heading 3', 'Heading 4', 'Heading 5', 'Heading 6', 'Blockquote', 'Code']"
|
|
59
|
-
@change="handleSelectChange"
|
|
60
|
-
/>
|
|
61
|
-
|
|
62
|
-
<template v-for="(action, index) in toolbarOptions">
|
|
58
|
+
<template v-for="(action, index) in toolbarOptions" :key="index">
|
|
63
59
|
<Btn
|
|
64
60
|
v-if="action.name !== 'separator' && config.includes(action.name)"
|
|
65
|
-
:key="action.name"
|
|
66
61
|
v-tooltip="action.label"
|
|
62
|
+
:icon="action.icon"
|
|
67
63
|
thin
|
|
68
64
|
flat
|
|
65
|
+
:aria-label="action.name"
|
|
69
66
|
:class="action.class"
|
|
70
67
|
class="radius-05"
|
|
71
|
-
|
|
72
|
-
:icon="action.icon"
|
|
73
|
-
@click="emit('action', action.name)"
|
|
68
|
+
@click="emit('action', action.name, action.label)"
|
|
74
69
|
/>
|
|
75
70
|
<span
|
|
76
|
-
v-if="action.name === 'separator'"
|
|
71
|
+
v-else-if="action.name === 'separator'"
|
|
77
72
|
:key="`separator-${index}`"
|
|
78
73
|
class=" opacity-2 mb-025"
|
|
79
74
|
>|</span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
let modal: any
|
|
2
2
|
|
|
3
3
|
export function applyFormatting(command: string, value: string = '') {
|
|
4
4
|
const selection = window.getSelection()
|
|
@@ -7,6 +7,9 @@ export function applyFormatting(command: string, value: string = '') {
|
|
|
7
7
|
const span = document.createElement('span')
|
|
8
8
|
|
|
9
9
|
switch (command) {
|
|
10
|
+
case 'formatBlock':
|
|
11
|
+
formatBlock(value)
|
|
12
|
+
break
|
|
10
13
|
case 'bold':
|
|
11
14
|
span.style.fontWeight = 'bold'
|
|
12
15
|
break
|
|
@@ -73,7 +76,7 @@ export function applyFormatting(command: string, value: string = '') {
|
|
|
73
76
|
case 'decreaseFontSize':
|
|
74
77
|
decreaseFontSize()
|
|
75
78
|
break
|
|
76
|
-
case '
|
|
79
|
+
case 'link':
|
|
77
80
|
insertLink()
|
|
78
81
|
break
|
|
79
82
|
case 'image':
|
|
@@ -91,6 +94,16 @@ export function applyFormatting(command: string, value: string = '') {
|
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
function formatBlock(value: string) {
|
|
98
|
+
if (!value) return
|
|
99
|
+
const selection = window.getSelection()
|
|
100
|
+
const range = selection?.getRangeAt(0)
|
|
101
|
+
if (!range) return
|
|
102
|
+
range.selectNodeContents(range.startContainer)
|
|
103
|
+
const el = document.createElement(value)
|
|
104
|
+
range.surroundContents(el)
|
|
105
|
+
}
|
|
106
|
+
|
|
94
107
|
function increaseFontSize() {
|
|
95
108
|
const selection = window.getSelection()
|
|
96
109
|
if (selection && selection.rangeCount > 0) {
|
|
@@ -104,7 +117,15 @@ function increaseFontSize() {
|
|
|
104
117
|
}
|
|
105
118
|
|
|
106
119
|
function decreaseFontSize() {
|
|
107
|
-
|
|
120
|
+
const selection = window.getSelection()
|
|
121
|
+
if (selection && selection.rangeCount > 0) {
|
|
122
|
+
const range = selection.getRangeAt(0)
|
|
123
|
+
const span = document.createElement('span')
|
|
124
|
+
const currentFontSize = Number.parseInt((range.startContainer.parentNode as HTMLElement).style.fontSize || '16', 10)
|
|
125
|
+
const newFontSize = currentFontSize - 2
|
|
126
|
+
span.style.fontSize = `${newFontSize}px`
|
|
127
|
+
range.surroundContents(span)
|
|
128
|
+
}
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
function removeFormatting() {
|
|
@@ -142,36 +163,40 @@ function insertList(type: string) {
|
|
|
142
163
|
}
|
|
143
164
|
|
|
144
165
|
export function insertLink() {
|
|
145
|
-
const
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
166
|
+
const selection = window.getSelection()
|
|
167
|
+
if (!selection || selection.rangeCount < 1) return
|
|
168
|
+
const range = selection.getRangeAt(0)
|
|
169
|
+
modal.showModalForm({ title: 'Insert Link', schema: [
|
|
170
|
+
{ id: 'url', $el: 'text', label: 'URL' },
|
|
171
|
+
{ id: 'openInNewTab', $el: 'check', label: 'Open in new tab' },
|
|
172
|
+
], onSubmit: (data: any) => {
|
|
173
|
+
const { url, openInNewTab } = data
|
|
174
|
+
if (url) {
|
|
150
175
|
const anchor = document.createElement('a')
|
|
151
176
|
anchor.href = url
|
|
152
177
|
range.surroundContents(anchor)
|
|
178
|
+
if (openInNewTab) anchor.target = '_blank'
|
|
153
179
|
}
|
|
154
|
-
}
|
|
180
|
+
} })
|
|
155
181
|
}
|
|
156
182
|
|
|
157
183
|
export function insertImage() {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
showModalForm({ title: 'Upload Image', schema: [
|
|
162
|
-
|
|
184
|
+
const selection = window.getSelection()
|
|
185
|
+
if (!selection || selection.rangeCount < 1) return
|
|
186
|
+
const range = selection.getRangeAt(0)
|
|
187
|
+
modal.showModalForm({ title: 'Upload Image', schema: [
|
|
188
|
+
{ id: 'src', $el: 'file', attrs: { bindkey: 'url' } },
|
|
189
|
+
{ id: 'alt', $el: 'text', label: 'Alt Text' },
|
|
190
|
+
], onSubmit: (_data: any) => {
|
|
191
|
+
const { src } = _data
|
|
192
|
+
if (src) {
|
|
193
|
+
const img = document.createElement('img')
|
|
194
|
+
img.src = src
|
|
195
|
+
img.alt = _data.alt
|
|
196
|
+
range.deleteContents()
|
|
197
|
+
range.insertNode(img)
|
|
198
|
+
}
|
|
163
199
|
} })
|
|
164
|
-
// const url = prompt('Enter the image URL:')
|
|
165
|
-
// if (url) {
|
|
166
|
-
// const selection = window.getSelection()
|
|
167
|
-
// if (selection && selection.rangeCount > 0) {
|
|
168
|
-
// const range = selection.getRangeAt(0)
|
|
169
|
-
// const img = document.createElement('img')
|
|
170
|
-
// img.src = url
|
|
171
|
-
// range.deleteContents()
|
|
172
|
-
// range.insertNode(img)
|
|
173
|
-
// }
|
|
174
|
-
// }
|
|
175
200
|
}
|
|
176
201
|
|
|
177
202
|
export function createTable() {
|
|
@@ -200,3 +225,22 @@ export function createTable() {
|
|
|
200
225
|
}
|
|
201
226
|
}
|
|
202
227
|
}
|
|
228
|
+
|
|
229
|
+
function clearFormatting() {
|
|
230
|
+
const selection = window.getSelection()
|
|
231
|
+
const range = selection?.getRangeAt(0)
|
|
232
|
+
if (!range) return
|
|
233
|
+
range.selectNodeContents(range.startContainer)
|
|
234
|
+
const contents = range.extractContents()
|
|
235
|
+
const text = contents.textContent
|
|
236
|
+
if (text !== null && text !== '') {
|
|
237
|
+
range.deleteContents()
|
|
238
|
+
const textNode = document.createTextNode(`${text}`)
|
|
239
|
+
setTimeout(() => { range.insertNode(textNode) }, 1)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function useFormatting(modalInstance?: any) {
|
|
244
|
+
modal = modalInstance
|
|
245
|
+
return { applyFormatting, clearFormatting }
|
|
246
|
+
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { ToolbarConfig } from './richtext-types'
|
|
3
|
+
import { useModal } from '@bagelink/vue'
|
|
3
4
|
import { onMounted, watch } from 'vue'
|
|
4
|
-
import {
|
|
5
|
+
import { useFormatting } from './formatting'
|
|
5
6
|
import Toolbar from './Toolbar.vue'
|
|
6
7
|
|
|
7
8
|
const props = defineProps<{ modelValue: string, toolbarConfig?: ToolbarConfig }>()
|
|
8
9
|
const emit = defineEmits(['update:modelValue'])
|
|
9
10
|
|
|
11
|
+
const modal = useModal()
|
|
12
|
+
const { applyFormatting, clearFormatting } = useFormatting(modal)
|
|
13
|
+
|
|
10
14
|
const editableContent = $ref<HTMLElement | undefined>()
|
|
11
15
|
const defaultConfig: ToolbarConfig = [
|
|
16
|
+
'formatBlock',
|
|
12
17
|
'bold',
|
|
13
18
|
'italic',
|
|
14
19
|
'underline',
|
|
@@ -47,41 +52,37 @@ function updateContent() {
|
|
|
47
52
|
emit('update:modelValue', contentHtml)
|
|
48
53
|
}
|
|
49
54
|
|
|
55
|
+
function updateToolbarHighlight() {
|
|
56
|
+
if (document.getSelection()) {
|
|
57
|
+
const selection = document.getSelection()
|
|
58
|
+
const range = selection?.rangeCount ? selection.getRangeAt(0) : null
|
|
59
|
+
const container = range?.commonAncestorContainer as HTMLElement
|
|
60
|
+
if (container) {
|
|
61
|
+
let currentElement = container.nodeType === 3 ? container.parentElement : container
|
|
62
|
+
while (currentElement && currentElement !== editableContent) {
|
|
63
|
+
if (['H1', 'H2', 'H3'].includes(currentElement.tagName)) {
|
|
64
|
+
// emit('action', { type: currentElement.tagName.toLowerCase() }); // Emit the tag to highlight button
|
|
65
|
+
break
|
|
66
|
+
}
|
|
67
|
+
currentElement = currentElement.parentElement
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
document.addEventListener('selectionchange', updateToolbarHighlight)
|
|
74
|
+
|
|
50
75
|
type ToolbarAction = 'link' | 'image' | 'table' | 'youtube' | 'fontSize' | 'fontFamily' | 'textColor' | 'backgroundColor' | 'bold' | 'italic' | 'underline' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'alignJustify' | 'orderedList' | 'unorderedList' | 'indent' | 'outdent' | 'blockquote' | 'codeBlock' | 'splitView' | 'codeView' | 'clear' | 'fullScreen'
|
|
51
76
|
|
|
52
77
|
function handleToolbarAction(action: string, value?: string) {
|
|
53
78
|
if (!editableContent) return
|
|
54
79
|
if (['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'].includes(action))
|
|
55
80
|
value = action.replace('align', '').toLowerCase()
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
applyFormatting('insertOrderedList')
|
|
62
|
-
break
|
|
63
|
-
case 'unorderedList':
|
|
64
|
-
applyFormatting('insertUnorderedList')
|
|
65
|
-
break
|
|
66
|
-
case 'blockquote':
|
|
67
|
-
applyFormatting('formatBlock', '<blockquote>')
|
|
68
|
-
break
|
|
69
|
-
case 'codeBlock':
|
|
70
|
-
applyFormatting('formatBlock', '<pre>')
|
|
71
|
-
break
|
|
72
|
-
case 'splitView':
|
|
73
|
-
isSplitView = !isSplitView
|
|
74
|
-
break
|
|
75
|
-
case 'codeView':
|
|
76
|
-
isCodeView = !isCodeView
|
|
77
|
-
break
|
|
78
|
-
case 'fullScreen':
|
|
79
|
-
toggleFullScreen()
|
|
80
|
-
break
|
|
81
|
-
default:
|
|
82
|
-
applyFormatting(action, value)
|
|
83
|
-
break
|
|
84
|
-
}
|
|
81
|
+
if (action === 'splitView') isSplitView = !isSplitView
|
|
82
|
+
else if (action === 'codeView') isCodeView = !isCodeView
|
|
83
|
+
else if (action === 'fullScreen') toggleFullScreen()
|
|
84
|
+
else if (action === 'clear') clearFormatting()
|
|
85
|
+
else applyFormatting(action, value)
|
|
85
86
|
updateContent()
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -143,10 +144,10 @@ function logInput(e: InputEvent) {
|
|
|
143
144
|
</script>
|
|
144
145
|
|
|
145
146
|
<template>
|
|
146
|
-
<div class="rich-text-editor rounded pt-05 px-
|
|
147
|
+
<div class="rich-text-editor rounded pt-05 px-05 pb-1">
|
|
147
148
|
<Toolbar :config @action="handleToolbarAction" />
|
|
148
149
|
<div class="editor-container flex flex-stretch gap-1 m_column">
|
|
149
|
-
<div class="content-area radius-05 p-1
|
|
150
|
+
<div class="content-area radius-05 p-1 w-100 grid">
|
|
150
151
|
<textarea v-if="isCodeView" v-model="contentHtml" @input="updateContent" />
|
|
151
152
|
<div
|
|
152
153
|
v-else
|
|
@@ -160,7 +161,13 @@ function logInput(e: InputEvent) {
|
|
|
160
161
|
@keydown="handleKeyDown"
|
|
161
162
|
/>
|
|
162
163
|
</div>
|
|
163
|
-
<code
|
|
164
|
+
<code
|
|
165
|
+
v-if="isSplitView"
|
|
166
|
+
contenteditable="true"
|
|
167
|
+
class="preview-area w-100 radius-05 p-1"
|
|
168
|
+
@input="(e) => logInput(e as InputEvent)"
|
|
169
|
+
v-text="contentHtml"
|
|
170
|
+
/>
|
|
164
171
|
</div>
|
|
165
172
|
</div>
|
|
166
173
|
</template>
|
|
@@ -10,8 +10,8 @@ export { default as PasswordInput } from './PasswordInput.vue'
|
|
|
10
10
|
export { default as RadioGroup } from './RadioGroup.vue'
|
|
11
11
|
export { default as RadioPillsInput } from './RadioPillsInput.vue'
|
|
12
12
|
export { default as RangeInput } from './RangeInput.vue'
|
|
13
|
-
export { default as
|
|
14
|
-
export { default as
|
|
13
|
+
export { default as RichText2 } from './RichText.vue'
|
|
14
|
+
export { default as RichText } from './RichText2/index.vue'
|
|
15
15
|
export { default as SelectInput } from './SelectInput.vue'
|
|
16
16
|
export { default as SignaturePad } from './SignaturePad.vue'
|
|
17
17
|
export { default as TableField } from './TableField.vue'
|