Improved Editor

This commit is contained in:
Grzegorz Leoniec 2019-01-23 21:36:53 +01:00
parent 83cc6e5377
commit 0673e0f823
No known key found for this signature in database
GPG Key ID: 3AA43686D4EB1377
2 changed files with 205 additions and 20 deletions

View File

@ -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;

View 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'
}
}
})
]
}
}