From 5986e599fdab63a3ac3f64ef1275d2fed7e39ad9 Mon Sep 17 00:00:00 2001 From: koehr <n@koehr.in> Date: Wed, 1 Apr 2020 16:54:04 +0200 Subject: [PATCH] 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 --- src/components/deck-card-editor-menu.vue | 4 +-- src/components/deck-card-editor.vue | 17 +++++++--- src/{editor.ts => editor/constants.ts} | 10 ------ src/editor/index.ts | 40 ++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 16 deletions(-) rename src/{editor.ts => editor/constants.ts} (72%) create mode 100644 src/editor/index.ts diff --git a/src/components/deck-card-editor-menu.vue b/src/components/deck-card-editor-menu.vue index 8c5004a..7d830b7 100644 --- a/src/components/deck-card-editor-menu.vue +++ b/src/components/deck-card-editor-menu.vue @@ -17,7 +17,7 @@ <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator' -import { blocks, State } from '@/editor.ts' +import { blocks, State } from '@/editor' @Component export default class DeckCardEditorMenu extends Vue { @@ -50,7 +50,7 @@ export default class DeckCardEditorMenu extends Vue { padding: .2rem 1rem; visibility: hidden; opacity: 0; - transition: opacity 0.2s, visibility 0.2s; + transition: opacity .3s .2s, visibility .3s .2s; background-color: var(--highlight-color); z-index: 2; } diff --git a/src/components/deck-card-editor.vue b/src/components/deck-card-editor.vue index 765a2ce..e161209 100644 --- a/src/components/deck-card-editor.vue +++ b/src/components/deck-card-editor.vue @@ -7,7 +7,7 @@ /> <div - :ref="content" + ref="content" class="card-content" :contenteditable="active" @focus="start" @@ -30,13 +30,14 @@ import { Component, Prop, Vue } from 'vue-property-decorator' import DeckCardEditorMenu from '@/components/deck-card-editor-menu.vue' import { elementNameToMenuState, + menuActionToCommand, getElementAndParentName, marks, blocks, State, movementKeys, controlSequenceKeys -} from '@/editor.ts' +} from '@/editor' @Component({ components: { DeckCardEditorMenu } @@ -91,7 +92,13 @@ export default class DeckCardEditor extends Vue { private editorAction (action: string) { 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 () { @@ -121,6 +128,8 @@ export default class DeckCardEditor extends Vue { private start () { this.contentInFocus = true this.syncMenuState() + // insert paragraphs instead of DIVs on enter + document.execCommand('defaultParagraphSeparator', false, 'p') } private stop () { @@ -129,7 +138,7 @@ export default class DeckCardEditor extends Vue { } </script> -<style scoped> +<style> .card-content p { margin: 0; line-height: 1.2; diff --git a/src/editor.ts b/src/editor/constants.ts similarity index 72% rename from src/editor.ts rename to src/editor/constants.ts index a5aefc4..10146f6 100644 --- a/src/editor.ts +++ b/src/editor/constants.ts @@ -1,5 +1,3 @@ -export type State = KV<boolean> - export const movementKeys = [ 'ArrowLeft', 'ArrowRight', @@ -37,11 +35,3 @@ export const blocks = [ 'separator', 'statBlock' ] - -export function getElementAndParentName (el: Node) { - const element = el.nodeName === '#text' ? el.parentElement : el - return [ - element?.nodeName, - element?.parentElement?.nodeName - ] -} diff --git a/src/editor/index.ts b/src/editor/index.ts new file mode 100644 index 0000000..9c51e66 --- /dev/null +++ b/src/editor/index.ts @@ -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 + ] +}