tiptapify 0.0.2 → 0.0.5
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 +5 -2
- package/dist/tiptapify.css +1 -1
- package/dist/tiptapify.es.js +19743 -18910
- package/dist/tiptapify.umd.js +39 -32
- package/package.json +23 -10
- package/src/components/MenuBubble.vue +9 -1
- package/src/components/Toolbar/Index.vue +3 -1
- package/src/components/Toolbar/fonts.ts +118 -0
- package/src/components/Toolbar/items.ts +52 -33
- package/src/components/editorExtensions.ts +3 -1
- package/src/components/extensions/components/LinkDialog.vue +1 -1
- package/src/components/extensions/components/ShowSource.vue +124 -0
- package/src/components/extensions/view-source.ts +53 -0
- package/src/i18n/locales/de.json +67 -0
- package/src/i18n/locales/en.json +13 -3
- package/src/i18n/locales/es.json +67 -0
- package/src/i18n/locales/fr.json +67 -0
- package/src/i18n/locales/it.json +67 -0
- package/src/i18n/locales/pl.json +67 -0
- package/src/i18n/locales/ru.json +13 -3
- package/src/i18n/locales/ua.json +13 -3
- package/components.d.ts +0 -20
- package/tsconfig.json +0 -22
- package/vite.config.ts +0 -86
package/package.json
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiptapify",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Tiptap3 editor with Vuetify3 menu implementation",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
|
-
"import":
|
|
8
|
-
|
|
7
|
+
"import": {
|
|
8
|
+
"default": "./dist/tiptapify.es.js",
|
|
9
|
+
"development": "./src/index.ts"
|
|
10
|
+
},
|
|
11
|
+
"require": {
|
|
12
|
+
"default": "./dist/tiptapify.umd.js",
|
|
13
|
+
"development": "./src/index.ts"
|
|
14
|
+
}
|
|
9
15
|
},
|
|
16
|
+
"./src/*": "./src/*",
|
|
17
|
+
"./dist/*": "./dist/*",
|
|
10
18
|
"./style.css": "./dist/tiptapify.css"
|
|
11
19
|
},
|
|
12
20
|
"main": "./dist/tiptapify.umd.cjs",
|
|
13
21
|
"module": "./dist/tiptapify.js",
|
|
22
|
+
"source": "./src/index.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"src"
|
|
26
|
+
],
|
|
14
27
|
"scripts": {
|
|
15
28
|
"dev": "vite",
|
|
16
29
|
"build": "vite build",
|
|
@@ -38,7 +51,6 @@
|
|
|
38
51
|
"repository": "https://github.com/IVoyt/tiptapify",
|
|
39
52
|
"packageManager": "pnpm@10.11.0",
|
|
40
53
|
"dependencies": {
|
|
41
|
-
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
|
42
54
|
"@tiptap/core": "next",
|
|
43
55
|
"@tiptap/extension-blockquote": "next",
|
|
44
56
|
"@tiptap/extension-bold": "next",
|
|
@@ -77,15 +89,9 @@
|
|
|
77
89
|
"@tiptap/starter-kit": "next",
|
|
78
90
|
"@tiptap/suggestion": "next",
|
|
79
91
|
"@tiptap/vue-3": "next",
|
|
80
|
-
"@vitejs/plugin-vue": "^5.2.4",
|
|
81
|
-
"@vitejs/plugin-vue-jsx": "^4.2.0",
|
|
82
92
|
"highlight.js": "^11.11.1",
|
|
83
93
|
"linkifyjs": "^4.3.1",
|
|
84
94
|
"lowlight": "^3.3.0",
|
|
85
|
-
"unplugin-vue-components": "^28.5.0",
|
|
86
|
-
"vite": "^6.3.5",
|
|
87
|
-
"vite-plugin-vuetify": "^2.1.1",
|
|
88
|
-
"vite-svg-loader": "^5.1.0",
|
|
89
95
|
"vue-i18n": "^11.1.4"
|
|
90
96
|
},
|
|
91
97
|
"peerDependencies": {
|
|
@@ -94,11 +100,18 @@
|
|
|
94
100
|
"vuetify": "^3.8.5"
|
|
95
101
|
},
|
|
96
102
|
"devDependencies": {
|
|
103
|
+
"@intlify/unplugin-vue-i18n": "^6.0.8",
|
|
97
104
|
"@rollup/plugin-alias": "^5.1.1",
|
|
98
105
|
"@types/node": "^22.15.21",
|
|
106
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
107
|
+
"@vitejs/plugin-vue-jsx": "^4.2.0",
|
|
99
108
|
"rollup-plugin-tsconfig-paths": "^1.5.2",
|
|
100
109
|
"sass-embedded": "^1.89.0",
|
|
101
110
|
"typescript": "^5.8.3",
|
|
111
|
+
"unplugin-vue-components": "^28.5.0",
|
|
112
|
+
"vite": "^6.3.5",
|
|
113
|
+
"vite-plugin-vuetify": "^2.1.1",
|
|
114
|
+
"vite-svg-loader": "^5.1.0",
|
|
102
115
|
"vite-tsconfig-paths": "^5.1.4",
|
|
103
116
|
"vue-tsc": "^2.2.10"
|
|
104
117
|
}
|
|
@@ -74,6 +74,14 @@ const items = ref([
|
|
|
74
74
|
disabled: computed(() => editorInstance.value.isActive('code') || editorInstance.value.isActive('codeBlock')),
|
|
75
75
|
},
|
|
76
76
|
click: () => linkAction(),
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'format clear',
|
|
80
|
+
icon: mdi.mdiFormatClear,
|
|
81
|
+
props: {
|
|
82
|
+
active: false,
|
|
83
|
+
},
|
|
84
|
+
click: () => editorInstance.value.chain().focus().unsetAllMarks().clearNodes().run(),
|
|
77
85
|
}
|
|
78
86
|
])
|
|
79
87
|
|
|
@@ -86,7 +94,7 @@ function linkAction() {
|
|
|
86
94
|
|
|
87
95
|
<template>
|
|
88
96
|
<!-- <BubbleMenu v-if="editorInstance" :editor="editorInstance" :tippy-options="{ duration: 100 }">-->
|
|
89
|
-
<BubbleMenu v-if="editorInstance" :editor="editorInstance">
|
|
97
|
+
<BubbleMenu v-if="editorInstance" :editor="editorInstance" :options="{ placement: 'bottom' }">
|
|
90
98
|
<div class="bubble-menu">
|
|
91
99
|
<VBtnToggle divided density="compact" :variant="variant">
|
|
92
100
|
<VBtn v-for="(item, key) in items" :key="key" v-bind="item.props" @click="item.click" size="small">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import LinkDialog from "@tiptapify/components/extensions/components/LinkDialog.vue";
|
|
3
|
+
import ShowSource from "@tiptapify/components/extensions/components/ShowSource.vue";
|
|
3
4
|
import { useEditor } from "@tiptapify/composable/useEditor";
|
|
4
5
|
import { computed, defineProps, Ref, ref } from 'vue'
|
|
5
6
|
import { useI18n } from "vue-i18n";
|
|
@@ -69,7 +70,7 @@ const toolbarItemsRef: Ref<ToolbarItemSections> = ref(items)
|
|
|
69
70
|
</VBtn>
|
|
70
71
|
</template>
|
|
71
72
|
|
|
72
|
-
<VList v-model="toolbarItem.modelValue">
|
|
73
|
+
<VList v-model="toolbarItem.modelValue" max-height="430px">
|
|
73
74
|
<VListItem
|
|
74
75
|
v-for="(item, menuItemKey) in toolbarItem.children"
|
|
75
76
|
:key="menuItemKey"
|
|
@@ -111,6 +112,7 @@ const toolbarItemsRef: Ref<ToolbarItemSections> = ref(items)
|
|
|
111
112
|
</template>
|
|
112
113
|
|
|
113
114
|
<LinkDialog ref="toolbarLinkButton" />
|
|
115
|
+
<ShowSource />
|
|
114
116
|
</div>
|
|
115
117
|
</template>
|
|
116
118
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export const fonts = [
|
|
2
|
+
{
|
|
3
|
+
name: 'Arial',
|
|
4
|
+
fontFamily: 'arial'
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
name: 'Arial Black',
|
|
8
|
+
fontFamily: 'arial black'
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'Baskerville',
|
|
12
|
+
fontFamily: 'baskerville'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'Bodoni MT',
|
|
16
|
+
fontFamily: 'bodoni mt'
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'Brush Script MT',
|
|
20
|
+
fontFamily: 'brush script mt'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Calibri',
|
|
24
|
+
fontFamily: 'calibri'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Calisto MT',
|
|
28
|
+
fontFamily: 'calisto mt'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'Cambria',
|
|
32
|
+
fontFamily: 'cambria'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Century Gothic',
|
|
36
|
+
fontFamily: 'century gothic'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Consolas',
|
|
40
|
+
fontFamily: 'consolas'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'Comic Sans',
|
|
44
|
+
fontFamily: 'comic sans ms, comic sans'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Courier',
|
|
48
|
+
fontFamily: 'Courier'
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Courier New',
|
|
52
|
+
fontFamily: 'courier new'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'Cursive',
|
|
56
|
+
fontFamily: 'cursive'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'Dejavu Sans',
|
|
60
|
+
fontFamily: 'dejavu sans'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'Franklin Gothic',
|
|
64
|
+
fontFamily: 'franklin gothic'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'Garamond',
|
|
68
|
+
fontFamily: 'garamond'
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'Georgia',
|
|
72
|
+
fontFamily: 'georgia'
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Helvetica',
|
|
76
|
+
fontFamily: 'helvetica'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'Impact',
|
|
80
|
+
fontFamily: 'impact'
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: 'Inter',
|
|
84
|
+
fontFamily: 'inter'
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'Monospace',
|
|
88
|
+
fontFamily: 'monospace'
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'Optima',
|
|
92
|
+
fontFamily: 'optima'
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'Segoe UI',
|
|
96
|
+
fontFamily: 'segoe ui'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'Serif',
|
|
100
|
+
fontFamily: 'serif'
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'Tahoma',
|
|
104
|
+
fontFamily: 'tahoma'
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'Time New Roman',
|
|
108
|
+
fontFamily: 'times new roman'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'Trebuchet MS',
|
|
112
|
+
fontFamily: 'trebuchet ms'
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'Verdana',
|
|
116
|
+
fontFamily: 'verdana'
|
|
117
|
+
},
|
|
118
|
+
]
|
|
@@ -1,28 +1,6 @@
|
|
|
1
1
|
import { computed, ComputedRef, Ref, ref } from "vue";
|
|
2
2
|
import * as mdi from '@mdi/js'
|
|
3
|
-
|
|
4
|
-
const fonts = ref([
|
|
5
|
-
{
|
|
6
|
-
name: 'Inter',
|
|
7
|
-
fontFamily: 'Inter'
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
name: 'Comic Sans',
|
|
11
|
-
fontFamily: 'Comic Sans MS, Comic Sans'
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
name: 'Serif',
|
|
15
|
-
fontFamily: 'serif'
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
name: 'Monospace',
|
|
19
|
-
fontFamily: 'monospace'
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
name: 'Cursive',
|
|
23
|
-
fontFamily: 'cursive'
|
|
24
|
-
},
|
|
25
|
-
])
|
|
3
|
+
import { fonts } from './fonts'
|
|
26
4
|
|
|
27
5
|
interface MDIIcons {
|
|
28
6
|
[key: string]: string
|
|
@@ -88,7 +66,6 @@ export function toolbarItems(
|
|
|
88
66
|
* font color, backgroundcolor
|
|
89
67
|
* tables
|
|
90
68
|
* media (image, video)
|
|
91
|
-
* unsetmarks, clearnodes
|
|
92
69
|
*/
|
|
93
70
|
heading: {
|
|
94
71
|
name: 'heading',
|
|
@@ -103,23 +80,41 @@ export function toolbarItems(
|
|
|
103
80
|
props: {
|
|
104
81
|
color: computed(() => editor.value.isActive('heading') ? 'primary' : ''),
|
|
105
82
|
},
|
|
106
|
-
children:
|
|
107
|
-
|
|
108
|
-
name: `
|
|
109
|
-
tooltip: `style.
|
|
110
|
-
icon: mdiIcons[`
|
|
83
|
+
children: [
|
|
84
|
+
{
|
|
85
|
+
name: `paragraph`,
|
|
86
|
+
tooltip: `style.paragraph`,
|
|
87
|
+
icon: mdiIcons[`mdiFormatParagraph`],
|
|
111
88
|
noI18n: true,
|
|
112
89
|
enabled: true,
|
|
113
90
|
props: {
|
|
114
91
|
color: computed(() => {
|
|
115
|
-
return editor.value.isActive('
|
|
92
|
+
return editor.value.isActive('paragraph') ? 'primary' : ''
|
|
116
93
|
}),
|
|
117
94
|
},
|
|
118
95
|
attrs: {
|
|
119
|
-
click: () => editor.value.chain().focus().
|
|
96
|
+
click: () => editor.value.chain().focus().setParagraph().run()
|
|
120
97
|
}
|
|
121
98
|
}
|
|
122
|
-
|
|
99
|
+
].concat(
|
|
100
|
+
headingLevels.value.map(level => {
|
|
101
|
+
return {
|
|
102
|
+
name: `H${level}`,
|
|
103
|
+
tooltip: `style.headings.h${level}`,
|
|
104
|
+
icon: mdiIcons[`mdiFormatHeader${level}`],
|
|
105
|
+
noI18n: true,
|
|
106
|
+
enabled: true,
|
|
107
|
+
props: {
|
|
108
|
+
color: computed(() => {
|
|
109
|
+
return editor.value.isActive('heading', { level }) ? 'primary' : ''
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
attrs: {
|
|
113
|
+
click: () => editor.value.chain().focus().toggleHeading({ level }).run()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
)
|
|
123
118
|
},
|
|
124
119
|
fontFamily: {
|
|
125
120
|
name: 'font-family',
|
|
@@ -131,7 +126,7 @@ export function toolbarItems(
|
|
|
131
126
|
attrs: {
|
|
132
127
|
click: () => editor.value.chain().focus().unsetFontFamily().run()
|
|
133
128
|
},
|
|
134
|
-
children: fonts.
|
|
129
|
+
children: fonts.map((font) => {
|
|
135
130
|
return {
|
|
136
131
|
name: font.name,
|
|
137
132
|
tooltip: '',
|
|
@@ -271,6 +266,19 @@ export function toolbarItems(
|
|
|
271
266
|
click: () => editor.value.chain().focus().toggleHighlight().run()
|
|
272
267
|
}
|
|
273
268
|
},
|
|
269
|
+
formatClear: {
|
|
270
|
+
name: 'format clear',
|
|
271
|
+
tooltip: 'format.formatClear',
|
|
272
|
+
icon: mdi.mdiFormatClear,
|
|
273
|
+
section: 'format',
|
|
274
|
+
enabled: true,
|
|
275
|
+
props: {
|
|
276
|
+
disabled: computed(() => !editor.value.can().chain().focus().unsetAllMarks().run()),
|
|
277
|
+
},
|
|
278
|
+
attrs: {
|
|
279
|
+
click: () => editor.value.chain().focus().unsetAllMarks().clearNodes().run()
|
|
280
|
+
}
|
|
281
|
+
},
|
|
274
282
|
|
|
275
283
|
code: {
|
|
276
284
|
name: 'code',
|
|
@@ -542,6 +550,17 @@ export function toolbarItems(
|
|
|
542
550
|
click: () => editor.value.chain().focus().setHardBreak().run()
|
|
543
551
|
}
|
|
544
552
|
},
|
|
553
|
+
source: {
|
|
554
|
+
name: 'source',
|
|
555
|
+
tooltip: 'misc.source',
|
|
556
|
+
icon: mdi.mdiCodeTags,
|
|
557
|
+
section: 'misc',
|
|
558
|
+
enabled: true,
|
|
559
|
+
props: {},
|
|
560
|
+
attrs: {
|
|
561
|
+
click: () => editor.value.commands.showSource()
|
|
562
|
+
}
|
|
563
|
+
},
|
|
545
564
|
}
|
|
546
565
|
|
|
547
566
|
|
|
@@ -25,6 +25,7 @@ import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'
|
|
|
25
25
|
|
|
26
26
|
import { Link } from '@tiptap/extension-link'
|
|
27
27
|
import CodeBlockComponent from '@tiptapify/components/CodeBlockComponent.vue'
|
|
28
|
+
import { ViewSource } from '@tiptapify/components/extensions/view-source'
|
|
28
29
|
import SlashCommands from '@tiptapify/components/extensions/slash-commands'
|
|
29
30
|
import suggestion from '@tiptapify/components/extensions/components/slashCommands/suggestion'
|
|
30
31
|
|
|
@@ -92,7 +93,8 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
|
|
|
92
93
|
types: ['heading', 'paragraph'],
|
|
93
94
|
}),
|
|
94
95
|
Placeholder.configure({ placeholder }),
|
|
95
|
-
CharacterCount
|
|
96
|
+
CharacterCount,
|
|
97
|
+
ViewSource
|
|
96
98
|
]
|
|
97
99
|
|
|
98
100
|
if (slashCommands) {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useEditor } from "@tiptapify/composable/useEditor";
|
|
3
|
+
import { ref, onMounted, onUnmounted, watch } from 'vue'
|
|
4
|
+
import { useI18n } from "vue-i18n";
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
indent: { type: Number, default: 2 },
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const { t } = useI18n();
|
|
11
|
+
|
|
12
|
+
const editor = useEditor().editor.getInstance()
|
|
13
|
+
|
|
14
|
+
const dialog = ref(false)
|
|
15
|
+
const formatted = ref(false)
|
|
16
|
+
const sourceCode = ref('')
|
|
17
|
+
|
|
18
|
+
const formatHtml = (html: string): string => {
|
|
19
|
+
let formatted = html.replace(/>/g, '>\n');
|
|
20
|
+
|
|
21
|
+
formatted = formatted.replace(/\n</g, '\n<');
|
|
22
|
+
formatted = formatted.replace(/([^>\n])</g, '$1\n<');
|
|
23
|
+
|
|
24
|
+
const lines = formatted.split('\n');
|
|
25
|
+
let indentLevel = 0;
|
|
26
|
+
|
|
27
|
+
return lines
|
|
28
|
+
.map(line => {
|
|
29
|
+
if (line.match(/<\//)) {
|
|
30
|
+
indentLevel = Math.max(0, indentLevel - 1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const indentedLine = ' '.repeat(indentLevel * props.indent) + line;
|
|
34
|
+
|
|
35
|
+
if (line.match(/<[^\/][^>]*>/) && !line.match(/<.*\/>/)) {
|
|
36
|
+
indentLevel++;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return indentedLine;
|
|
40
|
+
})
|
|
41
|
+
.filter(line => line.trim())
|
|
42
|
+
.join('\n');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const unformatHtml = (html: string): string => {
|
|
46
|
+
return html
|
|
47
|
+
.replace(/\n/g, '')
|
|
48
|
+
.replace(/\s+/g, ' ')
|
|
49
|
+
.replace(/>\s+</g, '><')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const showDialog = (event: CustomEvent) => {
|
|
53
|
+
sourceCode.value = event.detail.html
|
|
54
|
+
dialog.value = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const saveChanges = () => {
|
|
58
|
+
dialog.value = false
|
|
59
|
+
|
|
60
|
+
editor.value.commands.setContent(sourceCode.value, true)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
onMounted(() => {
|
|
64
|
+
window.addEventListener('tiptapify-show-source', showDialog as EventListener)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
onUnmounted(() => {
|
|
68
|
+
window.removeEventListener('tiptapify-show-source', showDialog as EventListener)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
watch(() => formatted.value, () => {
|
|
72
|
+
sourceCode.value = formatted.value ? formatHtml(sourceCode.value) : unformatHtml(sourceCode.value)
|
|
73
|
+
})
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<VDialog v-model="dialog" max-width="1500">
|
|
78
|
+
<VCard>
|
|
79
|
+
<VCardTitle>{{ t('dialog.source.title') }}</VCardTitle>
|
|
80
|
+
|
|
81
|
+
<VCardText>
|
|
82
|
+
<VContainer fluid class="pt-0 pl-0 pr-0">
|
|
83
|
+
<VRow>
|
|
84
|
+
<VCol>
|
|
85
|
+
<VBtn v-model="formatted" :color="`${formatted ? 'primary' : ''}`" @click="formatted = !formatted">
|
|
86
|
+
{{ t('dialog.source.prettify') }}
|
|
87
|
+
</VBtn>
|
|
88
|
+
</VCol>
|
|
89
|
+
</VRow>
|
|
90
|
+
</VContainer>
|
|
91
|
+
|
|
92
|
+
<VTextarea
|
|
93
|
+
v-model="sourceCode"
|
|
94
|
+
no-resize
|
|
95
|
+
rows="100"
|
|
96
|
+
variant="outlined"
|
|
97
|
+
class="source-code-area"
|
|
98
|
+
/>
|
|
99
|
+
</VCardText>
|
|
100
|
+
|
|
101
|
+
<VCardActions>
|
|
102
|
+
<VSpacer></VSpacer>
|
|
103
|
+
<VBtn color="primary" @click="dialog = false">
|
|
104
|
+
{{ t('dialog.close') }}
|
|
105
|
+
</VBtn>
|
|
106
|
+
<VBtn color="primary" @click="saveChanges">
|
|
107
|
+
{{ t('dialog.apply') }}
|
|
108
|
+
</VBtn>
|
|
109
|
+
</VCardActions>
|
|
110
|
+
</VCard>
|
|
111
|
+
</VDialog>
|
|
112
|
+
</template>
|
|
113
|
+
|
|
114
|
+
<style scoped lang="scss">
|
|
115
|
+
.source-code-area {
|
|
116
|
+
font-family: monospace;
|
|
117
|
+
white-space: pre-wrap;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
:deep(.source-code-area textarea) {
|
|
121
|
+
max-height: 900px;
|
|
122
|
+
overflow-y: auto;
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
/**
|
|
12
|
+
* Показать исходный HTML-код
|
|
13
|
+
*/
|
|
14
|
+
showSource: () => ReturnType
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ViewSource = Extension.create<ViewSourceOptions>({
|
|
20
|
+
name: 'viewSource',
|
|
21
|
+
|
|
22
|
+
addOptions() {
|
|
23
|
+
return {
|
|
24
|
+
HTMLAttributes: {},
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
addCommands() {
|
|
29
|
+
return {
|
|
30
|
+
showSource: () => ({ editor }) => {
|
|
31
|
+
const event = new CustomEvent('tiptapify-show-source', {
|
|
32
|
+
detail: {
|
|
33
|
+
// html: editor.getHTML()
|
|
34
|
+
html: editor.getHTML({ blockSeparator: '\n\n' })
|
|
35
|
+
// html: editor.getText({ blockSeparator: '\n\n' })
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
window.dispatchEvent(event)
|
|
40
|
+
|
|
41
|
+
return true
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
addProseMirrorPlugins() {
|
|
47
|
+
return [
|
|
48
|
+
new Plugin({
|
|
49
|
+
key: new PluginKey('viewSource'),
|
|
50
|
+
}),
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"style": {
|
|
3
|
+
"paragraph": "Absatz",
|
|
4
|
+
"heading": "Überschrift",
|
|
5
|
+
"headings": {
|
|
6
|
+
"h1": "Überschrift Ebene 1",
|
|
7
|
+
"h2": "Überschrift Ebene 2",
|
|
8
|
+
"h3": "Überschrift Ebene 3",
|
|
9
|
+
"h4": "Überschrift Ebene 4",
|
|
10
|
+
"h5": "Überschrift Ebene 5",
|
|
11
|
+
"h6": "Überschrift Ebene 6"
|
|
12
|
+
},
|
|
13
|
+
"fontFamily": "Schriftart",
|
|
14
|
+
"fontSize": "Schriftgröße",
|
|
15
|
+
"lineHeight": "Zeilenhöhe"
|
|
16
|
+
},
|
|
17
|
+
"format": {
|
|
18
|
+
"bold": "Fett",
|
|
19
|
+
"italic": "Kursiv",
|
|
20
|
+
"strike": "Durchgestrichen",
|
|
21
|
+
"underline": "Unterstrichen",
|
|
22
|
+
"sup": "Hochgestellt",
|
|
23
|
+
"sub": "Tiefgestellt",
|
|
24
|
+
"break": "Zeilenumbruch",
|
|
25
|
+
"highlight": "Hervorheben",
|
|
26
|
+
"line": "Horizontale Linie",
|
|
27
|
+
"blockquote": "Zitat",
|
|
28
|
+
"code": "Code",
|
|
29
|
+
"codeblock": "Codeblock",
|
|
30
|
+
"link": "Externer Link",
|
|
31
|
+
"formatClear": "Formatierung löschen"
|
|
32
|
+
},
|
|
33
|
+
"action": {
|
|
34
|
+
"undo": "Rückgängig",
|
|
35
|
+
"redo": "Wiederherstellen"
|
|
36
|
+
},
|
|
37
|
+
"alignment": "Ausrichtung",
|
|
38
|
+
"alignments": {
|
|
39
|
+
"left": "Linksbündig",
|
|
40
|
+
"center": "Zentriert",
|
|
41
|
+
"right": "Rechtsbündig",
|
|
42
|
+
"justify": "Blocksatz"
|
|
43
|
+
},
|
|
44
|
+
"list": "Liste",
|
|
45
|
+
"lists": {
|
|
46
|
+
"bullet": "Aufzählungsliste",
|
|
47
|
+
"numbered": "Nummerierte Liste",
|
|
48
|
+
"task": "Aufgabenliste",
|
|
49
|
+
"indent": "Einzug vergrößern",
|
|
50
|
+
"outdent": "Einzug verkleinern"
|
|
51
|
+
},
|
|
52
|
+
"dialog": {
|
|
53
|
+
"close": "Schließen",
|
|
54
|
+
"apply": "Anwenden",
|
|
55
|
+
"link": {
|
|
56
|
+
"title": "Link hinzufügen/bearbeiten",
|
|
57
|
+
"placeholder": "Linkadresse"
|
|
58
|
+
},
|
|
59
|
+
"source": {
|
|
60
|
+
"title": "Quellcode anzeigen",
|
|
61
|
+
"prettify": "prettify"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"misc": {
|
|
65
|
+
"source": "Quellcode anzeigen"
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/i18n/locales/en.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"style": {
|
|
3
|
+
"paragraph": "paragraph",
|
|
3
4
|
"heading": "heading",
|
|
4
5
|
"headings": {
|
|
5
6
|
"h1": "heading level 1",
|
|
@@ -26,7 +27,8 @@
|
|
|
26
27
|
"blockquote": "cite",
|
|
27
28
|
"code": "code",
|
|
28
29
|
"codeblock": "code block",
|
|
29
|
-
"link": "external link"
|
|
30
|
+
"link": "external link",
|
|
31
|
+
"formatClear": "format clear"
|
|
30
32
|
},
|
|
31
33
|
"action": {
|
|
32
34
|
"undo": "undo",
|
|
@@ -48,10 +50,18 @@
|
|
|
48
50
|
"outdent": "list item outdent"
|
|
49
51
|
},
|
|
50
52
|
"dialog": {
|
|
53
|
+
"close": "close",
|
|
54
|
+
"apply": "apply",
|
|
51
55
|
"link": {
|
|
52
56
|
"title": "add/edit link",
|
|
53
|
-
"placeholder": "link address"
|
|
54
|
-
|
|
57
|
+
"placeholder": "link address"
|
|
58
|
+
},
|
|
59
|
+
"source": {
|
|
60
|
+
"title": "view source code",
|
|
61
|
+
"prettify": "prettify"
|
|
55
62
|
}
|
|
63
|
+
},
|
|
64
|
+
"misc": {
|
|
65
|
+
"source": "view source code"
|
|
56
66
|
}
|
|
57
67
|
}
|