Skip to content

Commit

Permalink
feat: comment module setting
Browse files Browse the repository at this point in the history
  • Loading branch information
lovefieldFE committed May 31, 2023
1 parent 8007e5e commit 06d7465
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 31 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "dragon-editor",
"version": "2.0.0-beta",
"description": "WYSIWYG editor - DragonEditor",
"version": "2.0.0-beta.1",
"description": "WYSIWYG editor on Nuxt.js",
"repository": {
"type": "git",
"url": "git+https://github.com/lovefields/dragonEditor.git"
Expand Down
37 changes: 37 additions & 0 deletions playground/pages/comment.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<div>
Comment!

<button @click="addOption">옵션!</button>
<button @click="getStatus">상태!</button>
<div class="editor">
<DragonEditorComment v-model="contentData" ref="editor" />
</div>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted } from "#imports";
const contentData = ref({
type: "comment",
classList: [],
content: ""
});
const editor = ref();
function addOption() {
editor.value.setStyles("font-3322");
getStatus();
}
function getStatus() {
console.log(editor.value.getCursorClassList());
}
</script>

<style>
.editor {
width: 800px;
}
</style>
1 change: 0 additions & 1 deletion src/core/utils/cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type {cursorSelection, arrangementCursorData} from "../../types";
import {findEditableElement} from "./element";

export function setCursor(target: Node, idx: number) {
console.log(target);
if (target) {
let $target: Node;

Expand Down
5 changes: 3 additions & 2 deletions src/core/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {textBlock, userCustomMenu, editorMenu} from "../../types/index";
import { textBlock, userCustomMenu, editorMenu } from "../../types/index";


function generateId() {
Expand Down Expand Up @@ -43,4 +43,5 @@ export function createBlock(name: string) {

export * from "./keyboard";
export * from "./cursor";
export * from "./style";
export * from "./style";
export * from "./element";
39 changes: 36 additions & 3 deletions src/core/utils/keyboard.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
let enterCount = 0;
import { getCursor, setCursor } from "./cursor";
import { findEditableElement, findChildNumber } from "./element"

let enterCount = 0;
function enterEvent(type: string, event: KeyboardEvent, addAction: Function) {
if (event.code === "Enter") {
if (enterCount === 0) {
enterCount += 1;

const brtag = document.createElement("br");
const useShift = event.shiftKey;


switch (type) {
case "comment":
event.preventDefault();
addBrEvent();
break;
default:
if (useShift === false) {
event.preventDefault();
addAction("addBlock", "text");
}
}

setTimeout(() => {
enterCount = 0;
}, 150)
} else {
event.preventDefault();
setTimeout(() => {
Expand Down Expand Up @@ -84,4 +89,32 @@ export function pasteText(type: string, value: string) {
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
}

function addBrEvent() {
const brTag = document.createElement("br");
const selection = window.getSelection() as Selection;
const range = document.createRange();

selection.deleteFromDocument();
selection.getRangeAt(0).insertNode(brTag);
range.setStart(brTag, 0);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);

const cursorData = getCursor();

if ((cursorData.startNode as Node).constructor.name !== "Text") {
const editableElement = findEditableElement(cursorData.startNode as HTMLElement) as HTMLElement;
const childList = editableElement.childNodes;
const childIdx = findChildNumber(editableElement, cursorData.startNode as HTMLElement);

if (childList[childList.length - 1].textContent?.length === 0) {
(childList[childIdx] as HTMLElement).insertAdjacentHTML("beforebegin", "<br>");
childList[childList.length - 1].remove();
} else {
setCursor(childList[childIdx + 1], 0);
}
}
}
26 changes: 9 additions & 17 deletions src/core/utils/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ function defaultDecorationMake(originData: allBlock, $target: HTMLElement, class

parentNode.innerHTML = htmlStructure;
setTimeout(() => {
const $cursorTarget: HTMLElement = parentNode.childNodes[childNumber + 1] as HTMLElement;
let $cursorTarget: HTMLElement = editableElement.childNodes[childNumber + 1] as HTMLElement;
if (!$cursorTarget) {
$cursorTarget = editableElement.childNodes[childNumber] as HTMLElement;
}
const cursorLength: number = ($cursorTarget.textContent as string).length;

setCursor($cursorTarget, cursorLength);
Expand Down Expand Up @@ -274,17 +277,6 @@ function defaultDecorationMake(originData: allBlock, $target: HTMLElement, class
return originData;
}

function arrangementDecoration(originData: allBlock, $target: HTMLElement, className: string): allBlock {
let rawData: allBlock = originData;

switch (originData.type) {
default:
rawData = defaultDecorationMake(originData, $target, className);
}

return rawData;
}

export function styleSettings(type: string, blockData: allBlock, $target: HTMLElement) {
let rawData: allBlock = blockData;

Expand All @@ -299,19 +291,19 @@ export function styleSettings(type: string, blockData: allBlock, $target: HTMLEl
rawData.classList = arrangementAlignClass(rawData.classList, "d-align-right");
break;
case "decorationBold" :
rawData = arrangementDecoration(rawData, $target, "d-deco-bold");
rawData = defaultDecorationMake(rawData, $target, "d-deco-bold");
break;
case "decorationItalic" :
rawData = arrangementDecoration(rawData, $target, "d-deco-italic");
rawData = defaultDecorationMake(rawData, $target, "d-deco-italic");
break;
case "decorationUnderline" :
rawData = arrangementDecoration(rawData, $target, "d-deco-underline");
rawData = defaultDecorationMake(rawData, $target, "d-deco-underline");
break;
case "decorationStrikethrough" :
rawData = arrangementDecoration(rawData, $target, "d-deco-through");
rawData = defaultDecorationMake(rawData, $target, "d-deco-through");
break;
default:
rawData = arrangementDecoration(rawData, $target, type);
rawData = defaultDecorationMake(rawData, $target, type);
}

return rawData;
Expand Down
6 changes: 3 additions & 3 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {defineNuxtModule, addComponentsDir, createResolver} from '@nuxt/kit'
import {defineNuxtModule, addComponentsDir, createResolver} from "@nuxt/kit"

export default defineNuxtModule({
meta: {
name: 'dragon-editor',
name: "dragon-editor",
},
setup(options, nuxt) {
const resolver = createResolver(import.meta.url)

addComponentsDir(resolver.resolve('./shared/components'));
addComponentsDir(resolver.resolve("./shared/components"));
}
})
130 changes: 129 additions & 1 deletion src/shared/components/DragonEditorComment.vue
Original file line number Diff line number Diff line change
@@ -1 +1,129 @@
<template></template>
<template>
<div class="dragon-editor">
<p class="d-text-block" :class="data.classList" contenteditable v-html="data.content" @keydown="textKeyboardEvent"
@paste="pasteEvent" ref="$block"></p>
</div>
</template>

<script setup lang="ts">
import { ref, unref } from "#imports";
import {
keyboardEvent,
setCursor,
pasteText,
styleSettings,
getArrangementCursorData,
getClipboardData,
getCursor,
findEditableElement
} from "../../core/utils/index";
import { commentBlock } from "../../types/index";
const $block = ref();
const data = ref<commentBlock>({
type: "comment",
classList: [],
content: "",
});
const props = defineProps<{ modelValue: commentBlock }>();
const emit = defineEmits<{
(e: "update:modelValue", modelValue: commentBlock): void;
}>();
data.value = unref(props.modelValue) as commentBlock;
function textKeyboardEvent(e: KeyboardEvent) {
keyboardEvent("comment", e, emit);
}
function pasteEvent(e: ClipboardEvent) {
e.preventDefault();
const data = getClipboardData(e.clipboardData as DataTransfer);
if (data.type === "text") {
pasteText("text", data.value as string);
}
}
// export event
function updateBlockData() {
// 데이터 정규화 및 검수
const blockClassList = [...$block.value.classList];
blockClassList.splice(0, 1);
const pushList = blockClassList.filter(
(item) => data.value.classList.indexOf(item) === -1
);
data.value.classList = data.value.classList.concat(pushList);
// 커서위치 재지정
if ($block.value.innerHTML.length > 0) {
const cursorData = getArrangementCursorData();
data.value.content = $block.value.innerHTML;
emit("update:modelValue", data.value);
setTimeout(() => {
setCursor(
$block.value.childNodes[cursorData.childCount],
cursorData.length
);
// 빈 태그 삭제
$block.value.childNodes.forEach((child: ChildNode) => {
if (
child.constructor.name !== "Text" &&
child.textContent === ""
) {
child.remove();
}
});
}, 100);
} else {
emit("update:modelValue", data.value);
}
}
function focus() {
setCursor($block.value, 0);
}
function setStyles(kind: string) {
data.value = styleSettings(kind, data.value, $block.value);
setTimeout(() => {
updateBlockData();
}, 250);
}
function getCursorClassList(className: string) {
const cursorData = getCursor();
let value: string[] = [];
if (cursorData.type === "Caret") {
const type = (cursorData.startNode as Node).constructor.name;
const editableElement = findEditableElement(cursorData.startNode as Node);
let $target = cursorData.startNode as HTMLElement;
if (type === "Text") {
$target = (cursorData.startNode as HTMLElement).parentNode as HTMLElement;
}
if ($target !== editableElement) {
value = [...$target.classList];
}
}
return value;
}
defineExpose({
updateBlockData,
focus,
setStyles,
getCursorClassList
});
</script>

<style>
@import "../../core/style/common.css";
</style>
10 changes: 8 additions & 2 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export interface editorOptions {
customStyleMenu?: userStyleMenu[];
}

export type allBlock = (textBlock);
export type allBlock = (textBlock | commentBlock);

export type editorContentType = (textBlock)[];
export type editorContentType = allBlock[];

// Block types
export interface textBlock {
Expand All @@ -36,6 +36,12 @@ export interface textBlock {
content: string,
}

export interface commentBlock {
type: string;
classList: string[],
content: string,
}


// detail type
export interface cursorSelection {
Expand Down

0 comments on commit 06d7465

Please sign in to comment.