mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Improved Editor
This commit is contained in:
parent
83cc6e5377
commit
0673e0f823
@ -1,43 +1,152 @@
|
||||
<template>
|
||||
<editor-content
|
||||
:editor="editor"
|
||||
class="editor"
|
||||
/>
|
||||
<div class="editor">
|
||||
<editor-floating-menu :editor="editor">
|
||||
<div
|
||||
slot-scope="{ commands, isActive, menu }"
|
||||
class="editor__floating-menu"
|
||||
:class="{ 'is-active': menu.isActive }"
|
||||
:style="`top: ${menu.top}px`"
|
||||
>
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.paragraph()"
|
||||
@click.prevent="commands.paragraph()"
|
||||
>
|
||||
<ds-icon name="paragraph" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.heading({ level: 2 })"
|
||||
@click.prevent="commands.heading({ level: 2 })"
|
||||
>
|
||||
H2
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.heading({ level: 3 })"
|
||||
@click.prevent="commands.heading({ level: 3 })"
|
||||
>
|
||||
H3
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.bullet_list()"
|
||||
@click.prevent="commands.bullet_list()"
|
||||
>
|
||||
<ds-icon name="list-ul" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.ordered_list()"
|
||||
@click.prevent="commands.ordered_list()"
|
||||
>
|
||||
<ds-icon name="list-ol" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.blockquote()"
|
||||
@click.prevent="commands.blockquote"
|
||||
>
|
||||
<ds-icon name="quote-right" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.horizontal_rule()"
|
||||
@click.prevent="commands.horizontal_rule"
|
||||
>
|
||||
<ds-icon name="minus" />
|
||||
</ds-button>
|
||||
</div>
|
||||
</editor-floating-menu>
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import TactileEditorMenu from '~/components/editor/TactileEditorMenu.vue'
|
||||
import { Editor, EditorContent } from 'tiptap'
|
||||
import { Heading, ListItem, Placeholder, History } from 'tiptap-extensions'
|
||||
// import VoiceMark from '~/components/editor/marks/VoiceMark'
|
||||
// import QuoteMark from '~/components/editor/marks/QuoteMark'
|
||||
// import SoundMark from '~/components/editor/marks/SoundMark'
|
||||
import { Editor, EditorContent, EditorFloatingMenu } from 'tiptap'
|
||||
import EventHandler from './plugins/eventHandler.js'
|
||||
import {
|
||||
Heading,
|
||||
HardBreak,
|
||||
Blockquote,
|
||||
ListItem,
|
||||
BulletList,
|
||||
OrderedList,
|
||||
HorizontalRule,
|
||||
Placeholder,
|
||||
Bold,
|
||||
Italic,
|
||||
Strike,
|
||||
Underline,
|
||||
Link,
|
||||
History
|
||||
} from 'tiptap-extensions'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
// TactileEditorMenu,
|
||||
EditorContent
|
||||
EditorContent,
|
||||
EditorFloatingMenu
|
||||
},
|
||||
props: {
|
||||
html: { type: String, default: '' },
|
||||
doc: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: new Editor({
|
||||
doc: this.doc,
|
||||
extensions: [
|
||||
new Heading({ maxLevel: 2 }),
|
||||
new EventHandler(),
|
||||
new Heading(),
|
||||
new HardBreak(),
|
||||
new Blockquote(),
|
||||
new BulletList(),
|
||||
new OrderedList(),
|
||||
new HorizontalRule(),
|
||||
new Bold(),
|
||||
new Italic(),
|
||||
new Strike(),
|
||||
new Underline(),
|
||||
new Link(),
|
||||
new Heading({ levels: [2, 3] }),
|
||||
new ListItem(),
|
||||
// new VoiceMark(),
|
||||
// new QuoteMark(),
|
||||
// new SoundMark(),
|
||||
new Placeholder({
|
||||
emptyNodeClass: 'is-empty'
|
||||
emptyNodeClass: 'is-empty',
|
||||
emptyNodeText: 'Schreib etwas inspirerendes…'
|
||||
}),
|
||||
new History()
|
||||
]
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
html: {
|
||||
immediate: true,
|
||||
handler: function(html) {
|
||||
html = html
|
||||
.replace(/(<br\s*\/*>\s*){2,}/gim, '<br/>')
|
||||
.replace(/<\/p>\s*(<br\s*\/*>\s*)+\s*<p>/gim, '</p><p>')
|
||||
.replace(/<p>\s*(<br\s*\/*>\s*)+\s*<\/p>/gim, '')
|
||||
this.editor.setContent(html)
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
methods: {
|
||||
onDialog({ mark, key, name, focus }) {
|
||||
focus() // focus the editor if not already done to get the needed context
|
||||
@ -48,9 +157,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// @import '~assets/styles/variables';
|
||||
// @import '~assets/styles/marker';
|
||||
|
||||
.ProseMirror {
|
||||
padding: $space-small;
|
||||
min-height: $space-large;
|
||||
@ -60,6 +166,52 @@ export default {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.editor p.is-empty:first-child::before {
|
||||
content: attr(data-empty-text);
|
||||
float: left;
|
||||
color: $text-color-softer;
|
||||
padding-left: $space-base;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.menubar__button {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
li > p {
|
||||
margin-top: $space-xx-small;
|
||||
margin-bottom: $space-xx-small;
|
||||
}
|
||||
|
||||
.editor {
|
||||
&__floating-menu {
|
||||
position: absolute;
|
||||
margin-top: -0.25rem;
|
||||
margin-left: $space-base;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
background-color: #fff;
|
||||
|
||||
&.is-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
// p:not(.is-empty) {
|
||||
// br:first-of-type,
|
||||
// br:last-of-type {
|
||||
// display: none;
|
||||
// }
|
||||
// br + br + br {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/*.ProseMirror .is-empty:first-child::before {
|
||||
content: 'Füge hier deinen Text ein…';
|
||||
position: absolute;
|
||||
|
||||
33
components/Editor/plugins/eventHandler.js
Normal file
33
components/Editor/plugins/eventHandler.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { Extension, Plugin } from 'tiptap'
|
||||
import { Slice } from 'prosemirror-model'
|
||||
|
||||
export default class EventHandler extends Extension {
|
||||
get name() {
|
||||
return 'event_handler'
|
||||
}
|
||||
get plugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
handleDOMEvents: {
|
||||
drop(view, event) {
|
||||
event.stopImmediatePropagation()
|
||||
},
|
||||
paste(view, event, slice) {
|
||||
console.log('#### PASTE', slice)
|
||||
return 'ABC'
|
||||
}
|
||||
},
|
||||
transformPasted(slice) {
|
||||
console.log('#### transformPasted', slice)
|
||||
return new Slice(slice.content, slice.openStart, slice.openEnd)
|
||||
},
|
||||
transformPastedHTML(html) {
|
||||
console.log('#### transformPastedHTML', html)
|
||||
return 'HELLO WORLD'
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user