implements basic menu functionalities

this includes standard block elements (headers, paragraphs, lists, rulers)
but not marks (bold, italic)
and for sure not special elements like the stat block
This commit is contained in:
koehr 2020-04-01 16:54:04 +02:00 committed by Norman
parent c64b9a95fb
commit 5fc559abac
4 changed files with 55 additions and 16 deletions

View file

@ -17,7 +17,7 @@
<script lang="ts"> <script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator' import { Component, Prop, Vue } from 'vue-property-decorator'
import { blocks, State } from '@/editor.ts' import { blocks, State } from '@/editor'
@Component @Component
export default class DeckCardEditorMenu extends Vue { export default class DeckCardEditorMenu extends Vue {
@ -50,7 +50,7 @@ export default class DeckCardEditorMenu extends Vue {
padding: .2rem 1rem; padding: .2rem 1rem;
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
transition: opacity 0.2s, visibility 0.2s; transition: opacity .3s .2s, visibility .3s .2s;
background-color: var(--highlight-color); background-color: var(--highlight-color);
z-index: 2; z-index: 2;
} }

View file

@ -7,7 +7,7 @@
/> />
<div <div
:ref="content" ref="content"
class="card-content" class="card-content"
:contenteditable="active" :contenteditable="active"
@focus="start" @focus="start"
@ -30,13 +30,14 @@ import { Component, Prop, Vue } from 'vue-property-decorator'
import DeckCardEditorMenu from '@/components/deck-card-editor-menu.vue' import DeckCardEditorMenu from '@/components/deck-card-editor-menu.vue'
import { import {
elementNameToMenuState, elementNameToMenuState,
menuActionToCommand,
getElementAndParentName, getElementAndParentName,
marks, marks,
blocks, blocks,
State, State,
movementKeys, movementKeys,
controlSequenceKeys controlSequenceKeys
} from '@/editor.ts' } from '@/editor'
@Component({ @Component({
components: { DeckCardEditorMenu } components: { DeckCardEditorMenu }
@ -91,7 +92,13 @@ export default class DeckCardEditor extends Vue {
private editorAction (action: string) { private editorAction (action: string) {
console.log('action', action) console.log('action', action)
// const content = this.$refs.content const content = this.$refs.content as HTMLElement
content.focus()
const cmd = menuActionToCommand[action]
cmd()
this.$nextTick(() => this.syncMenuState())
} }
private syncMenuState () { private syncMenuState () {
@ -121,6 +128,8 @@ export default class DeckCardEditor extends Vue {
private start () { private start () {
this.contentInFocus = true this.contentInFocus = true
this.syncMenuState() this.syncMenuState()
// insert paragraphs instead of DIVs on enter
document.execCommand('defaultParagraphSeparator', false, 'p')
} }
private stop () { private stop () {
@ -129,7 +138,7 @@ export default class DeckCardEditor extends Vue {
} }
</script> </script>
<style scoped> <style>
.card-content p { .card-content p {
margin: 0; margin: 0;
line-height: 1.2; line-height: 1.2;

View file

@ -1,5 +1,3 @@
export type State = KV<boolean>
export const movementKeys = [ export const movementKeys = [
'ArrowLeft', 'ArrowLeft',
'ArrowRight', 'ArrowRight',
@ -37,11 +35,3 @@ export const blocks = [
'separator', 'separator',
'statBlock' 'statBlock'
] ]
export function getElementAndParentName (el: Node) {
const element = el.nodeName === '#text' ? el.parentElement : el
return [
element?.nodeName,
element?.parentElement?.nodeName
]
}

40
src/editor/index.ts Normal file
View file

@ -0,0 +1,40 @@
export type State = KV<boolean>
export {
movementKeys,
controlSequenceKeys,
elementNameToMenuState,
marks,
blocks
} from './constants'
function simpleAction (cmd: string, arg?: string): () => boolean {
return () => {
return document.execCommand(cmd, false, arg)
}
}
function insertHorizontalRule (): () => boolean {
return () => {
const hr = document.execCommand('insertHorizontalRule')
const p = document.execCommand('formatblock', false, 'P')
return hr && p
}
}
export const menuActionToCommand: KV<() => boolean> = {
paragraph: simpleAction('formatblock', 'P'),
heading1: simpleAction('formatblock', 'H1'),
heading2: simpleAction('formatblock', 'H2'),
heading3: simpleAction('formatblock', 'H3'),
bulletList: simpleAction('insertUnorderedList'),
numberedList: simpleAction('insertOrderedList'),
separator: insertHorizontalRule()
}
export function getElementAndParentName (el: Node) {
const element = el.nodeName === '#text' ? el.parentElement : el
return [
element?.nodeName,
element?.parentElement?.nodeName
]
}