dragon-editor 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,12 @@ export const useEditorStore = defineStore("editorStore", {
6
6
  message: {
7
7
  linkTextNoStyle: "Link text can't set any style."
8
8
  },
9
+ controlBar: {
10
+ active: false,
11
+ x: 0,
12
+ y: 0,
13
+ $element: null
14
+ },
9
15
  $currentBlock: null,
10
16
  $editor: null,
11
17
  $content: null,
@@ -26,6 +32,18 @@ export const useEditorStore = defineStore("editorStore", {
26
32
  },
27
33
  setCurrentBlock(block) {
28
34
  this.$currentBlock = block;
35
+ },
36
+ setContrulBar(value) {
37
+ this.controlBar.$element = value;
38
+ },
39
+ controlBarActive() {
40
+ const currentRect = this.$currentBlock.getBoundingClientRect();
41
+ this.controlBar.active = true;
42
+ this.controlBar.x = Math.floor(currentRect.x + currentRect.width / 2);
43
+ this.controlBar.y = Math.floor(currentRect.y - 50);
44
+ },
45
+ controlBarDeactive() {
46
+ this.controlBar.active = false;
29
47
  }
30
48
  }
31
49
  });
@@ -1,6 +1,12 @@
1
1
  interface EditorStore {
2
2
  cursorData: DEditorCursor | null;
3
3
  message: { [key: string]: string };
4
+ controlBar: {
5
+ active: boolean;
6
+ x: number;
7
+ y: number;
8
+ $element: HTMLDivElement | null;
9
+ };
4
10
  $editor: HTMLDivElement | null;
5
11
  $content: HTMLDivElement | null;
6
12
  $currentBlock: HTMLElement | null;
@@ -32,11 +38,16 @@ interface DEImage {
32
38
  caption?: string;
33
39
  }
34
40
 
41
+ interface DECodeItem {
42
+ text: string;
43
+ code: string;
44
+ }
45
+
35
46
  type DEDecoration = "bold" | "italic" | "underline" | "strikethrough" | "code";
36
47
 
37
48
  type DETextalign = "left" | "right" | "center" | "justify";
38
49
 
39
- type DEBlock = "text" | "heading" | "ul" | "ol" | "image";
50
+ type DEBlock = "text" | "heading" | "ul" | "ol" | "image" | "code";
40
51
 
41
52
  // 컴포넌트 메서드용 타입
42
53
  interface DragonEditor {
@@ -68,14 +79,12 @@ interface DEListItem {
68
79
  textContent: string;
69
80
  }
70
81
 
71
- interface DEUListBlock {
72
- type: "ul";
73
- child: DEListItem[];
74
- }
82
+ type DEListStyle = "disc" | "square" | "decimal" | "lower-alpha" | "upper-alpha" | "lower-roman" | "upper-roman";
75
83
 
76
- interface DEOListBlock {
77
- type: "ol";
78
- pattern: "a" | "i" | "1" | "A" | "I";
84
+ interface DEListBlock {
85
+ type: "list";
86
+ element: "ul" | "ol";
87
+ style: DEListStyle;
79
88
  child: DEListItem[];
80
89
  }
81
90
 
@@ -89,10 +98,18 @@ interface DEImageBlock {
89
98
  classList: string[];
90
99
  }
91
100
 
101
+ interface DECodeBlock {
102
+ type: "code";
103
+ language: string;
104
+ theme: string;
105
+ filename: string;
106
+ textContent: string;
107
+ }
108
+
92
109
  interface DECustomBlock {
93
110
  type: "custom";
94
111
  classList: string[];
95
112
  textContent: string;
96
113
  }
97
114
 
98
- type DEContentData = (DETextBlock | DEHeadingBlock | DEUListBlock | DEOListBlock | DEImageBlock | DECustomBlock)[];
115
+ type DEContentData = (DETextBlock | DEHeadingBlock | DEListBlock | DEImageBlock | DECustomBlock | DECodeBlock)[];
@@ -1,11 +1,13 @@
1
+ import "../type.d.ts";
1
2
  export declare function _getBlockType(element: HTMLElement): {
2
3
  $element: Element;
3
4
  type: string;
4
5
  };
5
6
  export declare function _createTextBlock(data?: DETextBlock): HTMLParagraphElement;
6
7
  export declare function _createHeadingBlock(data: DEHeadingBlock): HTMLHeadingElement;
7
- export declare function _createListBlock(data: DEUListBlock | DEOListBlock): HTMLElement;
8
+ export declare function _createListBlock(data: DEListBlock): HTMLElement;
8
9
  export declare function _createListItemBlock(child?: DEListItem): HTMLLIElement;
9
10
  export declare function _createImageBlock(data: DEImageBlock): HTMLDivElement;
10
- export declare function generateId(): string;
11
+ export declare function _createCodeBlock(data: DECodeBlock): HTMLDivElement;
12
+ export declare function _generateId(): string;
11
13
  export declare function _createCustomBlock(data: DECustomBlock): HTMLDivElement;
@@ -1,3 +1,4 @@
1
+ import "../type.d.ts";
1
2
  export function _getBlockType(element) {
2
3
  const $block = element.closest(".de-block");
3
4
  let typeName;
@@ -14,6 +15,9 @@ export function _getBlockType(element) {
14
15
  case $block.classList.contains("de-image-block"):
15
16
  typeName = "image";
16
17
  break;
18
+ case $block.classList.contains("de-code-block"):
19
+ typeName = "code";
20
+ break;
17
21
  default:
18
22
  typeName = "other";
19
23
  }
@@ -34,7 +38,7 @@ export function _createTextBlock(data = { type: "text", classList: [], textConte
34
38
  export function _createHeadingBlock(data) {
35
39
  const $headingBlock = document.createElement(`h${data.level}`);
36
40
  if (data.id === "") {
37
- $headingBlock.id = generateId();
41
+ $headingBlock.id = _generateId();
38
42
  } else {
39
43
  $headingBlock.id = data.id;
40
44
  }
@@ -47,11 +51,9 @@ export function _createHeadingBlock(data) {
47
51
  return $headingBlock;
48
52
  }
49
53
  export function _createListBlock(data) {
50
- const $block = document.createElement(data.type);
54
+ const $block = document.createElement(data.element);
51
55
  $block.classList.add("de-block", "de-list-block");
52
- if (data.type === "ol") {
53
- $block.type = data.pattern ?? "1";
54
- }
56
+ $block.dataset["style"] = data.style;
55
57
  data.child.forEach((child) => {
56
58
  $block.appendChild(_createListItemBlock(child));
57
59
  });
@@ -75,12 +77,16 @@ export function _createImageBlock(data) {
75
77
  const $p = document.createElement("p");
76
78
  $wrap.classList.add("de-block", "de-image-block", ...data.classList);
77
79
  $div.classList.add("de-image-area");
78
- $div.dataset["maxwidth"] = String(data.maxWidth);
79
80
  $leftBtn.classList.add("de-btn", "de-btn-left");
80
81
  $rightBtn.classList.add("de-btn", "de-btn-right");
81
82
  $image.classList.add("de-img");
82
83
  $p.contentEditable = "true";
83
84
  $p.classList.add("de-caption");
85
+ if (data.width / data.height < 1) {
86
+ $div.dataset["maxwidth"] = "40";
87
+ } else {
88
+ $div.dataset["maxwidth"] = String(data.maxWidth);
89
+ }
84
90
  $image.src = data.src;
85
91
  $image.width = data.width;
86
92
  $image.height = data.height;
@@ -95,7 +101,34 @@ export function _createImageBlock(data) {
95
101
  $wrap.appendChild($p);
96
102
  return $wrap;
97
103
  }
98
- export function generateId() {
104
+ export function _createCodeBlock(data) {
105
+ const $wrap = document.createElement("div");
106
+ const $file = document.createElement("p");
107
+ const $lang = document.createElement("p");
108
+ const $pre = document.createElement("pre");
109
+ const $code = document.createElement("code");
110
+ $wrap.classList.add("de-block", "de-code-block");
111
+ $wrap.dataset["theme"] = data.theme;
112
+ $file.contentEditable = "true";
113
+ $file.classList.add("de-filename");
114
+ $lang.textContent = data.language;
115
+ $lang.classList.add("de-language");
116
+ $pre.classList.add("de-pre");
117
+ $code.contentEditable = "true";
118
+ $code.classList.add("de-code-content");
119
+ if (data.filename !== "") {
120
+ $file.textContent = data.filename;
121
+ }
122
+ if (data.textContent !== "") {
123
+ $code.innerHTML = data.textContent;
124
+ }
125
+ $pre.appendChild($code);
126
+ $wrap.appendChild($file);
127
+ $wrap.appendChild($lang);
128
+ $wrap.appendChild($pre);
129
+ return $wrap;
130
+ }
131
+ export function _generateId() {
99
132
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
100
133
  let str = "";
101
134
  for (let i = 0; i < 6; i++) {
@@ -1,15 +1,19 @@
1
1
  import { _clenupCursor } from "./cursor.mjs";
2
2
  import "../type.d.ts";
3
3
  export function _addBlockToContent($block, store) {
4
- if (store.cursorData === null) {
4
+ if (store.cursorData === null && store.$currentBlock === null) {
5
5
  store.$content.insertAdjacentElement("beforeend", $block);
6
6
  } else {
7
7
  _clenupCursor(store);
8
- let $target = store.cursorData.startNode;
9
- if ($target.constructor.name === "Text") {
10
- $target = $target.parentNode;
8
+ if (store.$currentBlock === null) {
9
+ let $target = store.cursorData.startNode;
10
+ if ($target.constructor.name === "Text") {
11
+ $target = $target.parentNode;
12
+ }
13
+ const $targetBlock = $target.closest(".de-block");
14
+ $targetBlock.insertAdjacentElement("afterend", $block);
15
+ } else {
16
+ store.$currentBlock.insertAdjacentElement("afterend", $block);
11
17
  }
12
- const $targetBlock = $target.closest(".de-block");
13
- $targetBlock.insertAdjacentElement("afterend", $block);
14
18
  }
15
19
  }
@@ -0,0 +1,9 @@
1
+ import type { Ref } from "vue";
2
+ import "../type.d.ts";
3
+ export declare function _getCodeBlockTheme(): DECodeItem[];
4
+ export declare function _getCodeBlockLanguage(): DECodeItem[];
5
+ export declare function _setCodeBlockTheme(store: any, theme: string): void;
6
+ export declare function _setCodeBlockLanguage(store: any, lang: string): void;
7
+ export declare function _updateCodeBlockStyle(store: any, themeRef: Ref<string>, langRef: Ref<string>): void;
8
+ export declare function _setListBlockStyle(store: any, style: DEListStyle): void;
9
+ export declare function _updateListBlockStyle(store: any, styleRef: Ref<DEListStyle>): void;
@@ -0,0 +1,172 @@
1
+ import { _getBlockType } from "./block.mjs";
2
+ import hljs from "highlight.js";
3
+ import "../type.d.ts";
4
+ export function _getCodeBlockTheme() {
5
+ return [
6
+ {
7
+ text: "GitHub",
8
+ code: "github"
9
+ },
10
+ {
11
+ text: "GitHub Dark Dimmed",
12
+ code: "github-dark-dimmed"
13
+ }
14
+ ];
15
+ }
16
+ export function _getCodeBlockLanguage() {
17
+ return [
18
+ {
19
+ text: "Plain Text",
20
+ code: "text"
21
+ },
22
+ {
23
+ text: "Bash",
24
+ code: "bash"
25
+ },
26
+ {
27
+ text: "C#",
28
+ code: "csharp"
29
+ },
30
+ {
31
+ text: "C",
32
+ code: "c"
33
+ },
34
+ {
35
+ text: "C++",
36
+ code: "cpp"
37
+ },
38
+ {
39
+ text: "CSS",
40
+ code: "css"
41
+ },
42
+ {
43
+ text: "Django",
44
+ code: "django"
45
+ },
46
+ {
47
+ text: "Dockerfile",
48
+ code: "dockerfile"
49
+ },
50
+ {
51
+ text: "Go",
52
+ code: "go"
53
+ },
54
+ {
55
+ text: "HTML, XML",
56
+ code: "html"
57
+ },
58
+ {
59
+ text: "JSON",
60
+ code: "json"
61
+ },
62
+ {
63
+ text: "Java",
64
+ code: "java"
65
+ },
66
+ {
67
+ text: "JavaScript",
68
+ code: "js"
69
+ },
70
+ {
71
+ text: "TypeScript",
72
+ code: "ts"
73
+ },
74
+ {
75
+ text: "Kotlin",
76
+ code: "kotlin"
77
+ },
78
+ {
79
+ text: "Lua",
80
+ code: "lua"
81
+ },
82
+ {
83
+ text: "Markdown",
84
+ code: "md"
85
+ },
86
+ {
87
+ text: "Nginx",
88
+ code: "nginx"
89
+ },
90
+ {
91
+ text: "PHP",
92
+ code: "php"
93
+ },
94
+ {
95
+ text: "Python",
96
+ code: "python"
97
+ },
98
+ {
99
+ text: "Ruby",
100
+ code: "ruby"
101
+ },
102
+ {
103
+ text: "SCSS",
104
+ code: "scss"
105
+ },
106
+ {
107
+ text: "SQL",
108
+ code: "sql"
109
+ },
110
+ {
111
+ text: "Shell",
112
+ code: "shell"
113
+ },
114
+ {
115
+ text: "Swift",
116
+ code: "swift"
117
+ },
118
+ {
119
+ text: "YAML",
120
+ code: "yml"
121
+ }
122
+ ];
123
+ }
124
+ export function _setCodeBlockTheme(store, theme) {
125
+ if (store.$currentBlock !== null) {
126
+ const { $element, type } = _getBlockType(store.$currentBlock);
127
+ if (type === "code") {
128
+ $element.dataset["theme"] = theme;
129
+ }
130
+ }
131
+ }
132
+ export function _setCodeBlockLanguage(store, lang) {
133
+ if (store.$currentBlock !== null) {
134
+ const { $element, type } = _getBlockType(store.$currentBlock);
135
+ if (type === "code") {
136
+ const $langText = $element.querySelector(".de-language");
137
+ const $code = $element.querySelector(".de-code-content");
138
+ const convert = hljs.highlight($code.textContent ?? "", { language: lang });
139
+ $langText.textContent = convert._top.name ?? "";
140
+ $code.innerHTML = convert.value;
141
+ }
142
+ }
143
+ }
144
+ export function _updateCodeBlockStyle(store, themeRef, langRef) {
145
+ if (store.$currentBlock !== null) {
146
+ const { $element, type } = _getBlockType(store.$currentBlock);
147
+ if (type === "code") {
148
+ const theme = $element.dataset["theme"] ?? "github";
149
+ const $langText = $element.querySelector(".de-language").textContent;
150
+ const langItem = _getCodeBlockLanguage().find((item) => item.text === $langText);
151
+ themeRef.value = theme;
152
+ langRef.value = langItem?.code ?? "Plain Text";
153
+ }
154
+ }
155
+ }
156
+ export function _setListBlockStyle(store, style) {
157
+ if (store.$currentBlock !== null) {
158
+ const { $element, type } = _getBlockType(store.$currentBlock);
159
+ if (type === "list") {
160
+ $element.dataset["style"] = style;
161
+ }
162
+ }
163
+ }
164
+ export function _updateListBlockStyle(store, styleRef) {
165
+ if (store.$currentBlock !== null) {
166
+ const { $element, type } = _getBlockType(store.$currentBlock);
167
+ if (type === "list") {
168
+ const style = $element.dataset["style"];
169
+ styleRef.value = style;
170
+ }
171
+ }
172
+ }
@@ -1,4 +1,4 @@
1
- import { _createTextBlock, _createHeadingBlock, _createListBlock, _createImageBlock, _createCustomBlock } from "./block.mjs";
1
+ import { _createTextBlock, _createHeadingBlock, _createListBlock, _createImageBlock, _createCodeBlock, _createCustomBlock } from "./block.mjs";
2
2
  import "../type.d.ts";
3
3
  export function _getContentData($content) {
4
4
  const childList = $content.children;
@@ -19,12 +19,8 @@ export function _getContentData($content) {
19
19
  data.push(converteHeadingToData($child, 3));
20
20
  break;
21
21
  case "UL":
22
- data.push(converteUListToData($child));
23
- break;
24
22
  case "OL":
25
- data.push(converteOListToData($child));
26
- break;
27
- case "PRE":
23
+ data.push(converteListToData($child));
28
24
  break;
29
25
  case "DIV":
30
26
  data.push(converteDivToData($child));
@@ -43,22 +39,14 @@ export function _setContentData(data, store) {
43
39
  case "heading":
44
40
  childList.push(_createHeadingBlock(item));
45
41
  break;
46
- case "ul":
47
- case "ol":
42
+ case "list":
48
43
  childList.push(_createListBlock(item));
49
44
  break;
50
45
  case "image":
51
- childList.push(
52
- _createImageBlock({
53
- type: item.type,
54
- src: item.src,
55
- maxWidth: item.maxWidth,
56
- width: item.width,
57
- height: item.height,
58
- caption: item.caption,
59
- classList: item.classList
60
- })
61
- );
46
+ childList.push(_createImageBlock(item));
47
+ break;
48
+ case "code":
49
+ childList.push(_createCodeBlock(item));
62
50
  break;
63
51
  case "custom":
64
52
  childList.push(_createCustomBlock(item));
@@ -83,21 +71,11 @@ function converteHeadingToData($child, level) {
83
71
  textContent: $child.innerHTML
84
72
  };
85
73
  }
86
- function converteUListToData($child) {
87
- return {
88
- type: "ul",
89
- child: [...$child.children].map(($li) => {
90
- return {
91
- classList: getClassListWithoutDefaultClass($li),
92
- textContent: $li.innerHTML
93
- };
94
- })
95
- };
96
- }
97
- function converteOListToData($child) {
74
+ function converteListToData($child) {
98
75
  return {
99
- type: "ol",
100
- pattern: $child.type,
76
+ type: "list",
77
+ element: $child.tagName.toLowerCase(),
78
+ style: $child.dataset["style"],
101
79
  child: [...$child.children].map(($li) => {
102
80
  return {
103
81
  classList: getClassListWithoutDefaultClass($li),
@@ -112,6 +90,9 @@ function converteDivToData($child) {
112
90
  case $child.classList.contains("de-image-block"):
113
91
  data = convertImageBlock($child);
114
92
  break;
93
+ case $child.classList.contains("de-code-block"):
94
+ data = convertCodeBlock($child);
95
+ break;
115
96
  case $child.classList.contains("de-custom-block"):
116
97
  data = convertCustomBlock($child);
117
98
  break;
@@ -132,6 +113,18 @@ function convertImageBlock($imageBlock) {
132
113
  classList: getClassListWithoutDefaultClass($imageBlock)
133
114
  };
134
115
  }
116
+ function convertCodeBlock($codeBlock) {
117
+ const $code = $codeBlock.querySelector(".de-code-content");
118
+ const $file = $codeBlock.querySelector(".de-filename");
119
+ const $lang = $codeBlock.querySelector(".de-language");
120
+ return {
121
+ type: "code",
122
+ theme: $codeBlock.dataset["theme"],
123
+ filename: $file?.textContent ?? "",
124
+ language: $lang?.textContent ?? "text",
125
+ textContent: $code?.innerHTML ?? ""
126
+ };
127
+ }
135
128
  function convertCustomBlock($block) {
136
129
  return {
137
130
  type: "custom",
@@ -6,5 +6,5 @@ export declare function _hotKeyEvent(event: KeyboardEvent, store: any): void;
6
6
  /**
7
7
  * 복사 & 붙여넣기 이벤트
8
8
  */
9
- export declare function copyEvent(event: KeyboardEvent, store: any): void;
10
- export declare function pasteEvent(event: KeyboardEvent, store: any): void;
9
+ export declare function _copyEvent(event: ClipboardEvent, store: any): void;
10
+ export declare function _pasteEvent(event: ClipboardEvent, store: any, emit: any): Promise<void>;