tiptapify 0.0.25 → 0.0.27
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/README.md +1 -0
- package/dist/tiptapify.css +1 -1
- package/dist/tiptapify.mjs +9317 -9123
- package/dist/tiptapify.umd.js +38 -38
- package/package.json +1 -1
- package/src/components/Tiptapify.vue +34 -23
- package/src/components/Toolbar/Index.vue +14 -0
- package/src/components/Toolbar/misc.ts +5 -0
- package/src/components/UI/BtnIcon.vue +3 -3
- package/src/components/UI/TiptapifyDialog.vue +5 -1
- package/src/components/editorExtensions.ts +3 -4
- package/src/extensions/components/list/bullet/Button.vue +98 -3
- package/src/extensions/components/list/bullet/index.ts +101 -0
- package/src/extensions/components/misc/fullscreen/Button.vue +61 -0
- package/src/extensions/components/misc/preview/index.ts +0 -41
- package/src/extensions/components/misc/source/index.ts +0 -49
package/package.json
CHANGED
|
@@ -93,30 +93,34 @@ onBeforeUnmount(() => {
|
|
|
93
93
|
</script>
|
|
94
94
|
|
|
95
95
|
<template>
|
|
96
|
-
<
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
96
|
+
<div :id="`tiptapify-editor-${editor?.instanceId}`">
|
|
97
|
+
<div>
|
|
98
|
+
<template v-if="toolbar">
|
|
99
|
+
<Toolbar
|
|
100
|
+
v-if="editor"
|
|
101
|
+
:variant-btn="variantBtn"
|
|
102
|
+
:variant-field="variantField"
|
|
103
|
+
:font-measure="fontMeasure"
|
|
104
|
+
:items="propsItems"
|
|
105
|
+
:items-exclude="propsItemsExclude"
|
|
106
|
+
:rounded="rounded"
|
|
107
|
+
:custom-extensions="customExtensions"
|
|
108
|
+
:theme="currentTheme"
|
|
109
|
+
/>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<div :class="`border border-t-0 rounded-b-${rounded}`">
|
|
113
|
+
<div class="pa-2 tiptapify-container resizable" :style="`${height > 0 ? `height: ${height}px` : ''}`">
|
|
114
|
+
<MenuFloating v-if="floatingMenu" :variant="variantBtn" :theme="currentTheme" />
|
|
115
|
+
|
|
116
|
+
<MenuBubble v-if="bubbleMenu" :variant="variantBtn" :theme="currentTheme" />
|
|
117
|
+
|
|
118
|
+
<EditorContent :editor="editor" class="tiptapify-editor" />
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<Footer :show-words-count="showWordsCount" :show-characters-count="showCharactersCount" />
|
|
122
|
+
</div>
|
|
117
123
|
</div>
|
|
118
|
-
|
|
119
|
-
<Footer :show-words-count="showWordsCount" :show-characters-count="showCharactersCount" />
|
|
120
124
|
</div>
|
|
121
125
|
</template>
|
|
122
126
|
|
|
@@ -410,5 +414,12 @@ onBeforeUnmount(() => {
|
|
|
410
414
|
cursor: col-resize;
|
|
411
415
|
}
|
|
412
416
|
|
|
417
|
+
ul.list-style-circle {
|
|
418
|
+
list-style-type: circle !important;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
ul.list-style-square {
|
|
422
|
+
list-style-type: square !important;
|
|
423
|
+
}
|
|
413
424
|
}
|
|
414
425
|
</style>
|
|
@@ -125,6 +125,20 @@ function addToolbarItem(_toolbarItems: toolbarItemsType, itemsList: any, itemTit
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
if (_itemTitle === 'bulletList' && _itemOptions.length > 0) {
|
|
129
|
+
const paragraphIndex = _itemOptions.findIndex((item: any) => item === 'p')
|
|
130
|
+
const withParagraph = paragraphIndex > -1
|
|
131
|
+
if (withParagraph) {
|
|
132
|
+
_itemOptions.splice(paragraphIndex, 1)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
component.props = {
|
|
136
|
+
withDisc: _itemOptions.includes('disc'),
|
|
137
|
+
withCircle: _itemOptions.includes('circle'),
|
|
138
|
+
withSquare: _itemOptions.includes('square'),
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
128
142
|
_toolbarItems[itemSection].components.push(component)
|
|
129
143
|
|
|
130
144
|
return true
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { default as LineButton } from "@tiptapify/extensions/components/misc/line/Button.vue";
|
|
2
2
|
import { default as BreakButton } from "@tiptapify/extensions/components/misc/break/Button.vue";
|
|
3
3
|
import { default as PreviewButton } from "@tiptapify/extensions/components/misc/preview/Button.vue";
|
|
4
|
+
import { default as FullscreenButton } from "@tiptapify/extensions/components/misc/fullscreen/Button.vue";
|
|
4
5
|
import { default as SourceButton } from "@tiptapify/extensions/components/misc/source/Button.vue";
|
|
5
6
|
import { default as InvisibleCharButton } from "@tiptapify/extensions/components/misc/invisibleChar/Button.vue";
|
|
6
7
|
import { default as FormatClearButton } from "@tiptapify/extensions/components/misc/formatClear/Button.vue";
|
|
@@ -26,6 +27,10 @@ export default {
|
|
|
26
27
|
name: 'preview',
|
|
27
28
|
component: markRaw(PreviewButton),
|
|
28
29
|
},
|
|
30
|
+
{
|
|
31
|
+
name: 'fullscreen',
|
|
32
|
+
component: markRaw(FullscreenButton),
|
|
33
|
+
},
|
|
29
34
|
{
|
|
30
35
|
name: 'formatClear',
|
|
31
36
|
component: markRaw(FormatClearButton),
|
|
@@ -13,12 +13,12 @@ const isSvgString = (icon: any) => {
|
|
|
13
13
|
|
|
14
14
|
<template>
|
|
15
15
|
<div v-if="isSvgString(icon)" v-html="icon" class="v-icon tiptapify-btn-svg-icon"></div>
|
|
16
|
-
<VIcon v-else :icon="icon || `mdiSvg:${mdi.mdiImageBrokenVariant}`" size="
|
|
16
|
+
<VIcon v-else :icon="icon || `mdiSvg:${mdi.mdiImageBrokenVariant}`" size="20" />
|
|
17
17
|
</template>
|
|
18
18
|
|
|
19
19
|
<style lang="scss" scoped>
|
|
20
20
|
.tiptapify-btn-svg-icon {
|
|
21
|
-
width:
|
|
22
|
-
height:
|
|
21
|
+
width: 20px;
|
|
22
|
+
height: 20px;
|
|
23
23
|
}
|
|
24
24
|
</style>
|
|
@@ -105,7 +105,11 @@ watch(() => dialog.value, async () => {
|
|
|
105
105
|
<template>
|
|
106
106
|
<VDialog v-model="dialog" :max-width="maxWidth" :fullscreen="fullscreen" @click:outside="emitClose">
|
|
107
107
|
<VCard>
|
|
108
|
-
<VCardTitle
|
|
108
|
+
<VCardTitle
|
|
109
|
+
ref="movableHandler"
|
|
110
|
+
:class="`d-flex ${!fullscreen ? 'tiptapify-movable-handler' : ''}`"
|
|
111
|
+
style="user-select: none;"
|
|
112
|
+
>
|
|
109
113
|
<VLabel>
|
|
110
114
|
{{ title ?? t(`dialog.${module}.title`) }}
|
|
111
115
|
</VLabel>
|
|
@@ -25,12 +25,11 @@ import { TableKit } from '@tiptap/extension-table'
|
|
|
25
25
|
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'
|
|
26
26
|
import { InvisibleCharacters } from '@tiptap/extension-invisible-characters'
|
|
27
27
|
|
|
28
|
+
import { BulletListCircle, BulletListSquare } from '@tiptapify/extensions/components/list/bullet'
|
|
28
29
|
import { TiptapifyLink } from '@tiptapify/extensions/components/media/link'
|
|
29
30
|
import { TiptapifyImage } from '@tiptapify/extensions/components/media/image'
|
|
30
31
|
import { TiptapifyVideo } from '@tiptapify/extensions/components/media/video'
|
|
31
32
|
import CodeBlockComponent from '@tiptapify/extensions/components/CodeBlockComponent.vue'
|
|
32
|
-
import { ViewSource } from '@tiptapify/extensions/components/misc/source'
|
|
33
|
-
import { Preview } from '@tiptapify/extensions/components/misc/preview'
|
|
34
33
|
import SlashCommands from '@tiptapify/extensions/slash-commands'
|
|
35
34
|
import suggestion from '@tiptapify/extensions/components/slashCommands/suggestion'
|
|
36
35
|
import { toolbarSections } from "@tiptapify/types/toolbarTypes";
|
|
@@ -102,11 +101,11 @@ export function editorExtensions (placeholder: string, slashCommands: boolean, c
|
|
|
102
101
|
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
|
103
102
|
Placeholder.configure({ placeholder }),
|
|
104
103
|
CharacterCount,
|
|
105
|
-
ViewSource,
|
|
106
104
|
InvisibleCharacters.configure({
|
|
107
105
|
visible: false,
|
|
108
106
|
}),
|
|
109
|
-
|
|
107
|
+
BulletListCircle,
|
|
108
|
+
BulletListSquare
|
|
110
109
|
]
|
|
111
110
|
|
|
112
111
|
if (slashCommands) {
|
|
@@ -3,22 +3,117 @@
|
|
|
3
3
|
import * as mdi from '@mdi/js'
|
|
4
4
|
import { Editor } from "@tiptap/vue-3";
|
|
5
5
|
import BtnIcon from "@tiptapify/components/UI/BtnIcon.vue";
|
|
6
|
-
import { inject, Ref } from "vue";
|
|
6
|
+
import { computed, inject, ref, Ref, watch } from "vue";
|
|
7
7
|
|
|
8
8
|
import defaults from '@tiptapify/constants/defaults'
|
|
9
9
|
|
|
10
|
-
defineProps({
|
|
11
|
-
variantBtn: { type: String, default: defaults.variantBtn }
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
variantBtn: { type: String, default: defaults.variantBtn },
|
|
12
|
+
withDisc: { type: Boolean, default: true },
|
|
13
|
+
withCircle: { type: Boolean, default: true },
|
|
14
|
+
withSquare: { type: Boolean, default: true }
|
|
12
15
|
})
|
|
13
16
|
|
|
14
17
|
const editor = inject('tiptapifyEditor') as Ref<Editor>
|
|
15
18
|
|
|
16
19
|
const { t } = inject('tiptapifyI18n') as any
|
|
17
20
|
|
|
21
|
+
const disc = computed(() => props.withDisc)
|
|
22
|
+
const circle = computed(() => props.withCircle)
|
|
23
|
+
const square = computed(() => props.withSquare)
|
|
24
|
+
|
|
25
|
+
const iconDisc = '<svg width="48" height="48" focusable="false" viewBox="5 5 32 32"><g fill-rule="evenodd"><circle cx="11" cy="14" r="3"></circle><circle cx="11" cy="24" r="3"></circle><circle cx="11" cy="34" r="3"></circle><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"></path></g></svg>'
|
|
26
|
+
const iconCircle = '<svg width="48" height="48" focusable="false" viewBox="5 5 32 32"><g fill-rule="evenodd"><path d="M11 16a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 26a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 36a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" fill-rule="nonzero"></path><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"></path></g></svg>'
|
|
27
|
+
const iconSquare = '<svg width="48" height="48" focusable="false" viewBox="5 5 32 32"><g fill-rule="evenodd"><path d="M8 11h6v6H8zM8 21h6v6H8zM8 31h6v6H8z"></path><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"></path>'
|
|
28
|
+
|
|
29
|
+
const bulletLists = ref({
|
|
30
|
+
disc: {
|
|
31
|
+
name: 'bulletList',
|
|
32
|
+
enabled: disc.value,
|
|
33
|
+
icon: iconDisc
|
|
34
|
+
},
|
|
35
|
+
circle: {
|
|
36
|
+
name: 'bulletListCircle',
|
|
37
|
+
enabled: circle.value,
|
|
38
|
+
icon: iconCircle
|
|
39
|
+
},
|
|
40
|
+
square: {
|
|
41
|
+
name: 'bulletListSquare',
|
|
42
|
+
enabled: square.value,
|
|
43
|
+
icon: iconSquare
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
const menuItems = ref({})
|
|
47
|
+
const isMenu = ref(false)
|
|
48
|
+
|
|
49
|
+
function checkButtonOrMenu() {
|
|
50
|
+
menuItems.value = Object.values(bulletLists.value).filter(item => item.enabled)
|
|
51
|
+
isMenu.value = menuItems.value.length > 1
|
|
52
|
+
}
|
|
53
|
+
checkButtonOrMenu()
|
|
54
|
+
|
|
55
|
+
function toggleList(listType: string) {
|
|
56
|
+
switch(listType) {
|
|
57
|
+
case 'disc': editor.value.commands.toggleBulletList(); break;
|
|
58
|
+
case 'circle': editor.value.commands.toggleBulletListCircle(); break;
|
|
59
|
+
case 'square': editor.value.commands.toggleBulletListSquare(); break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const buttonActive = computed(() => {
|
|
64
|
+
return editor.value.isActive('bulletList') ||
|
|
65
|
+
editor.value.isActive('bulletListCircle') ||
|
|
66
|
+
editor.value.isActive('bulletListSquare')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const buttonDisabled = computed(() => {
|
|
70
|
+
return !editor.value.can().chain().focus().toggleBulletList().run() &&
|
|
71
|
+
!editor.value.can().chain().focus().toggleBulletListCircle().run() &&
|
|
72
|
+
!editor.value.can().chain().focus().toggleBulletListSquare().run()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
watch(() => bulletLists.value, () => {
|
|
76
|
+
checkButtonOrMenu()
|
|
77
|
+
}, { deep: true, immediate: true })
|
|
18
78
|
</script>
|
|
19
79
|
|
|
20
80
|
<template>
|
|
81
|
+
<VMenu v-if="isMenu">
|
|
82
|
+
<template #activator="{ props: menuProps }">
|
|
83
|
+
<VBtn
|
|
84
|
+
:color="buttonActive ? 'primary' : ''"
|
|
85
|
+
:disabled="buttonDisabled"
|
|
86
|
+
:variant="variantBtn"
|
|
87
|
+
v-bind="menuProps"
|
|
88
|
+
size="32"
|
|
89
|
+
>
|
|
90
|
+
<VTooltip activator="parent">
|
|
91
|
+
{{ t('lists.bullet') }}
|
|
92
|
+
</VTooltip>
|
|
93
|
+
<BtnIcon :icon="`mdiSvg:${mdi.mdiFormatListBulleted}`" />
|
|
94
|
+
</VBtn>
|
|
95
|
+
</template>
|
|
96
|
+
|
|
97
|
+
<VList>
|
|
98
|
+
<VListItem
|
|
99
|
+
v-for="(bulletList, key) in menuItems"
|
|
100
|
+
:key="key"
|
|
101
|
+
link
|
|
102
|
+
:active="editor.isActive(bulletList.name)"
|
|
103
|
+
@click="toggleList(key)"
|
|
104
|
+
>
|
|
105
|
+
<VTooltip activator="parent">
|
|
106
|
+
{{ t('lists.bullet') }}
|
|
107
|
+
</VTooltip>
|
|
108
|
+
<VListItemTitle class="d-flex justify-center align-center">
|
|
109
|
+
<BtnIcon :icon="bulletList.icon" />
|
|
110
|
+
</VListItemTitle>
|
|
111
|
+
</VListItem>
|
|
112
|
+
</VList>
|
|
113
|
+
</VMenu>
|
|
114
|
+
|
|
21
115
|
<VBtn
|
|
116
|
+
v-else
|
|
22
117
|
:color="editor.isActive('bulletList') ? 'primary' : ''"
|
|
23
118
|
:disabled="!editor.can().chain().focus().toggleBulletList().run()"
|
|
24
119
|
:variant="variantBtn"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { BulletList } from "@tiptap/extension-list"
|
|
2
|
+
|
|
3
|
+
export const BulletListCircle = BulletList.extend({
|
|
4
|
+
name: 'bulletListCircle',
|
|
5
|
+
|
|
6
|
+
addAttributes() {
|
|
7
|
+
return {
|
|
8
|
+
class: {
|
|
9
|
+
default: null,
|
|
10
|
+
renderHTML: (attributes: any) => {
|
|
11
|
+
return {
|
|
12
|
+
class: `${attributes.class}`,
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
parseHTML: (element: any) => element.getAttribute('class'),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
addOptions() {
|
|
21
|
+
return {
|
|
22
|
+
itemTypeName: 'listItem',
|
|
23
|
+
HTMLAttributes: {
|
|
24
|
+
class: 'list-style-circle',
|
|
25
|
+
},
|
|
26
|
+
keepMarks: false,
|
|
27
|
+
keepAttributes: false,
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
parseHTML() {
|
|
32
|
+
return [
|
|
33
|
+
{ tag: 'ul', class: 'list-style-circle' }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
addCommands() {
|
|
38
|
+
return {
|
|
39
|
+
toggleBulletListCircle: () =>
|
|
40
|
+
({ commands, chain }) => {
|
|
41
|
+
if (this.options.keepAttributes) {
|
|
42
|
+
return chain()
|
|
43
|
+
.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)
|
|
44
|
+
.updateAttributes('listItem', this.editor.getAttributes('textStyle'))
|
|
45
|
+
.run()
|
|
46
|
+
}
|
|
47
|
+
return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
export const BulletListSquare = BulletList.extend({
|
|
54
|
+
name: 'bulletListSquare',
|
|
55
|
+
|
|
56
|
+
addAttributes() {
|
|
57
|
+
return {
|
|
58
|
+
class: {
|
|
59
|
+
default: null,
|
|
60
|
+
renderHTML: (attributes: any) => {
|
|
61
|
+
return {
|
|
62
|
+
class: `${attributes.class}`,
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
parseHTML: (element: any) => element.getAttribute('class'),
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
addOptions() {
|
|
71
|
+
return {
|
|
72
|
+
itemTypeName: 'listItem',
|
|
73
|
+
HTMLAttributes: {
|
|
74
|
+
class: 'list-style-square',
|
|
75
|
+
},
|
|
76
|
+
keepMarks: false,
|
|
77
|
+
keepAttributes: false,
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
parseHTML() {
|
|
82
|
+
return [
|
|
83
|
+
{ tag: 'ul', class: 'list-style-square' }
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
addCommands() {
|
|
88
|
+
return {
|
|
89
|
+
toggleBulletListSquare: () =>
|
|
90
|
+
({ commands, chain }) => {
|
|
91
|
+
if (this.options.keepAttributes) {
|
|
92
|
+
return chain()
|
|
93
|
+
.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)
|
|
94
|
+
.updateAttributes('listItem', this.editor.getAttributes('textStyle'))
|
|
95
|
+
.run()
|
|
96
|
+
}
|
|
97
|
+
return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks)
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
|
|
3
|
+
import * as mdi from '@mdi/js'
|
|
4
|
+
import { Editor } from "@tiptap/vue-3";
|
|
5
|
+
import BtnIcon from "@tiptapify/components/UI/BtnIcon.vue";
|
|
6
|
+
import { inject, nextTick, ref, Ref } from "vue";
|
|
7
|
+
|
|
8
|
+
import defaults from '@tiptapify/constants/defaults'
|
|
9
|
+
|
|
10
|
+
defineProps({
|
|
11
|
+
variantBtn: { type: String, default: defaults.variantBtn }
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const editor = inject('tiptapifyEditor') as Ref<Editor>
|
|
15
|
+
|
|
16
|
+
const { t } = inject('tiptapifyI18n') as any
|
|
17
|
+
|
|
18
|
+
const dialog = ref(false)
|
|
19
|
+
|
|
20
|
+
async function dialogOpen() {
|
|
21
|
+
dialog.value = true
|
|
22
|
+
|
|
23
|
+
await changeEditorContainer('tiptapify-editor', 'tiptapify-editor-fullscreen')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function dialogClose() {
|
|
27
|
+
dialog.value = false
|
|
28
|
+
|
|
29
|
+
await changeEditorContainer('tiptapify-editor-fullscreen', 'tiptapify-editor')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function changeEditorContainer(source: string, target: string) {
|
|
33
|
+
await nextTick()
|
|
34
|
+
|
|
35
|
+
const sourceElm = document.querySelector(`#${source}-${editor.value.instanceId} > div`);
|
|
36
|
+
|
|
37
|
+
const targetElm = document.querySelector(`#${target}-${editor.value.instanceId}`);
|
|
38
|
+
|
|
39
|
+
targetElm.appendChild(sourceElm);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<VBtn @click="dialog ? dialogClose() : dialogOpen()" size="32" :variant="variantBtn">
|
|
46
|
+
<VTooltip activator="parent">
|
|
47
|
+
{{ t('misc.preview') }}
|
|
48
|
+
</VTooltip>
|
|
49
|
+
<BtnIcon :icon="dialog ? `mdiSvg:${mdi.mdiFullscreenExit}` : `mdiSvg:${mdi.mdiFullscreen}`" />
|
|
50
|
+
</VBtn>
|
|
51
|
+
|
|
52
|
+
<VDialog v-model="dialog" fullscreen @close="dialogClose()" @update:modelValue="!dialog ? dialogClose() : ''">
|
|
53
|
+
<VCard>
|
|
54
|
+
<div :id="`tiptapify-editor-fullscreen-${editor?.instanceId}`"></div>
|
|
55
|
+
</VCard>
|
|
56
|
+
</VDialog>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<style lang="scss" scoped>
|
|
60
|
+
|
|
61
|
+
</style>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core'
|
|
2
|
-
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
3
|
-
|
|
4
|
-
const name: string = 'preview'
|
|
5
|
-
|
|
6
|
-
declare module '@tiptap/core' {
|
|
7
|
-
interface Commands<ReturnType> {
|
|
8
|
-
preview: {
|
|
9
|
-
showPreview: () => ReturnType
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const Preview = Extension.create({
|
|
15
|
-
name,
|
|
16
|
-
|
|
17
|
-
addCommands() {
|
|
18
|
-
return {
|
|
19
|
-
showPreview: () => ({ editor }) => {
|
|
20
|
-
const event = new CustomEvent(`tiptapify-show-${name}`, {
|
|
21
|
-
detail: {
|
|
22
|
-
html: editor.getHTML(),
|
|
23
|
-
editorId: editor.instanceId
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
window.dispatchEvent(event)
|
|
28
|
-
|
|
29
|
-
return true
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
addProseMirrorPlugins() {
|
|
35
|
-
return [
|
|
36
|
-
new Plugin({
|
|
37
|
-
key: new PluginKey(name),
|
|
38
|
-
}),
|
|
39
|
-
]
|
|
40
|
-
},
|
|
41
|
-
})
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { Extension } from '@tiptap/core'
|
|
2
|
-
import { Plugin, PluginKey } from '@tiptap/pm/state'
|
|
3
|
-
|
|
4
|
-
export interface ViewSourceOptions {
|
|
5
|
-
HTMLAttributes: Record<string, any>
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
declare module '@tiptap/core' {
|
|
9
|
-
interface Commands<ReturnType> {
|
|
10
|
-
viewSource: {
|
|
11
|
-
showSource: () => ReturnType
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const ViewSource = Extension.create<ViewSourceOptions>({
|
|
17
|
-
name: 'viewSource',
|
|
18
|
-
|
|
19
|
-
addOptions() {
|
|
20
|
-
return {
|
|
21
|
-
HTMLAttributes: {},
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
addCommands() {
|
|
26
|
-
return {
|
|
27
|
-
showSource: () => ({ editor }) => {
|
|
28
|
-
const event = new CustomEvent('tiptapify-show-source', {
|
|
29
|
-
detail: {
|
|
30
|
-
html: editor.getHTML(),
|
|
31
|
-
editorId: editor.instanceId
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
window.dispatchEvent(event)
|
|
36
|
-
|
|
37
|
-
return true
|
|
38
|
-
},
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
addProseMirrorPlugins() {
|
|
43
|
-
return [
|
|
44
|
-
new Plugin({
|
|
45
|
-
key: new PluginKey('viewSource'),
|
|
46
|
-
}),
|
|
47
|
-
]
|
|
48
|
-
},
|
|
49
|
-
})
|