dragon-editor 3.4.4 → 3.5.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.
- package/README.md +9 -15
- package/dist/module.d.mts +5 -0
- package/dist/module.json +8 -1
- package/dist/module.mjs +5 -3
- package/dist/runtime/components/DragonEditor.vue +252 -720
- package/dist/runtime/components/DragonEditorViewer.vue +59 -45
- package/dist/runtime/scss/editor.css +83 -34
- package/dist/runtime/scss/viewer.css +31 -4
- package/dist/runtime/type.d.ts +78 -23
- package/dist/runtime/utils/event/block.d.ts +0 -0
- package/dist/runtime/utils/event/block.js +78 -0
- package/dist/runtime/utils/event/cursor.d.ts +0 -0
- package/dist/runtime/utils/{cursor.mjs → event/cursor.js} +4 -16
- package/dist/runtime/utils/event/data.d.ts +0 -0
- package/dist/runtime/utils/event/data.js +342 -0
- package/dist/runtime/utils/event/index.d.ts +8 -0
- package/dist/runtime/utils/event/index.js +8 -0
- package/dist/runtime/utils/event/keyboard.d.ts +0 -0
- package/dist/runtime/utils/event/keyboard.js +1368 -0
- package/dist/runtime/utils/event/mouse.d.ts +0 -0
- package/dist/runtime/utils/event/mouse.js +70 -0
- package/dist/runtime/utils/event/scroll.d.ts +0 -0
- package/dist/runtime/utils/event/scroll.js +29 -0
- package/dist/runtime/utils/event/touch.d.ts +0 -0
- package/dist/runtime/utils/event/touch.js +10 -0
- package/dist/runtime/utils/event/window.d.ts +0 -0
- package/dist/runtime/utils/event/window.js +32 -0
- package/dist/runtime/utils/layout/block.d.ts +0 -0
- package/dist/runtime/utils/layout/block.js +105 -0
- package/dist/runtime/utils/layout/body.d.ts +0 -0
- package/dist/runtime/utils/layout/body.js +22 -0
- package/dist/runtime/utils/layout/controlbar.d.ts +0 -0
- package/dist/runtime/utils/layout/controlbar.js +99 -0
- package/dist/runtime/utils/layout/icon.d.ts +0 -0
- package/dist/runtime/utils/layout/icon.js +156 -0
- package/dist/runtime/utils/layout/index.d.ts +5 -0
- package/dist/runtime/utils/layout/index.js +5 -0
- package/dist/runtime/utils/layout/menuBar.d.ts +0 -0
- package/dist/runtime/utils/layout/menuBar.js +358 -0
- package/dist/runtime/utils/node/block.d.ts +0 -0
- package/dist/runtime/utils/node/block.js +235 -0
- package/dist/runtime/utils/{element.d.ts → node/element.d.ts} +1 -0
- package/dist/runtime/utils/{element.mjs → node/element.js} +19 -4
- package/dist/runtime/utils/node/index.d.ts +2 -0
- package/dist/runtime/utils/node/index.js +2 -0
- package/dist/runtime/utils/style/anchor.d.ts +0 -0
- package/dist/runtime/utils/style/anchor.js +240 -0
- package/dist/runtime/utils/style/decoration.d.ts +0 -0
- package/dist/runtime/utils/style/decoration.js +378 -0
- package/dist/runtime/utils/style/index.d.ts +2 -0
- package/dist/runtime/utils/style/index.js +2 -0
- package/dist/types.d.mts +7 -0
- package/dist/types.d.ts +3 -3
- package/package.json +15 -16
- package/dist/runtime/store.d.ts +0 -11
- package/dist/runtime/store.mjs +0 -51
- package/dist/runtime/utils/block.d.ts +0 -13
- package/dist/runtime/utils/block.mjs +0 -144
- package/dist/runtime/utils/content.d.ts +0 -2
- package/dist/runtime/utils/content.mjs +0 -19
- package/dist/runtime/utils/controlBar.d.ts +0 -9
- package/dist/runtime/utils/controlBar.mjs +0 -172
- package/dist/runtime/utils/convertor.d.ts +0 -3
- package/dist/runtime/utils/convertor.mjs +0 -138
- package/dist/runtime/utils/cursor.d.ts +0 -6
- package/dist/runtime/utils/keyboardEvent.d.ts +0 -10
- package/dist/runtime/utils/keyboardEvent.mjs +0 -978
- package/dist/runtime/utils/style.d.ts +0 -5
- package/dist/runtime/utils/style.mjs +0 -617
- /package/dist/runtime/{plugin.mjs → plugin.js} +0 -0
|
@@ -1,727 +1,210 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<div v-if="props.useMenuBar === true" class="de-menu-bar" :style="{ top: `${menuBarTop}px` }">
|
|
4
|
-
<div class="de-menu-wrap">
|
|
5
|
-
<button class="de-menu de-menu-add" @click="isActiveAddBlockMenu = !isActiveAddBlockMenu">
|
|
6
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
7
|
-
<path class="de-path" d="M50.6667 34.6668H34.6667V50.6668H29.3334V34.6668H13.3334V29.3335H29.3334V13.3335H34.6667V29.3335H50.6667V34.6668Z"></path>
|
|
8
|
-
</svg>
|
|
9
|
-
</button>
|
|
10
|
-
|
|
11
|
-
<button class="de-menu" @click="setDecoration('bold')">
|
|
12
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
13
|
-
<path class="de-path" d="M40.6 31.4402C43.1866 29.6535 45 26.7202 45 24.0002C45 17.9735 40.3333 13.3335 34.3333 13.3335H17.6666V50.6668H36.44C42.0133 50.6668 46.3333 46.1335 46.3333 40.5602C46.3333 36.5068 44.04 33.0402 40.6 31.4402ZM25.6666 20.0002H33.6666C35.88 20.0002 37.6666 21.7868 37.6666 24.0002C37.6666 26.2135 35.88 28.0002 33.6666 28.0002H25.6666V20.0002ZM35 44.0002H25.6666V36.0002H35C37.2133 36.0002 39 37.7868 39 40.0002C39 42.2135 37.2133 44.0002 35 44.0002Z"></path>
|
|
14
|
-
</svg>
|
|
15
|
-
</button>
|
|
16
|
-
|
|
17
|
-
<button class="de-menu" @click="setDecoration('italic')">
|
|
18
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
19
|
-
<path class="de-path" d="M26.6667 13.3335V21.3335H32.56L23.44 42.6668H16V50.6668H37.3333V42.6668H31.44L40.56 21.3335H48V13.3335H26.6667Z"></path>
|
|
20
|
-
</svg>
|
|
21
|
-
</button>
|
|
22
|
-
|
|
23
|
-
<button class="de-menu" @click="setDecoration('underline')">
|
|
24
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
25
|
-
<path class="de-path" d="M32 45.3333C40.8267 45.3333 48 38.16 48 29.3333V8H41.3334V29.3333C41.3334 34.48 37.1467 38.6667 32 38.6667C26.8534 38.6667 22.6667 34.48 22.6667 29.3333V8H16V29.3333C16 38.16 23.1734 45.3333 32 45.3333ZM13.3334 50.6667V56H50.6667V50.6667H13.3334Z"></path>
|
|
26
|
-
</svg>
|
|
27
|
-
</button>
|
|
28
|
-
|
|
29
|
-
<button class="de-menu" @click="setDecoration('strikethrough')">
|
|
30
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
31
|
-
<path class="de-path" d="M26.6667 52H37.3333V44H26.6667V52ZM13.3333 12V20H26.6667V28H37.3333V20H50.6667V12H13.3333ZM8 38.6667H56V33.3333H8V38.6667Z"></path>
|
|
32
|
-
</svg>
|
|
33
|
-
</button>
|
|
34
|
-
|
|
35
|
-
<button class="de-menu" @click="setDecoration('code')">
|
|
36
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
37
|
-
<path class="de-path" d="M25.0667 44.2667L12.8 32L25.0667 19.7333L21.3334 16L5.33337 32L21.3334 48L25.0667 44.2667ZM38.9334 44.2667L51.2 32L38.9334 19.7333L42.6667 16L58.6667 32L42.6667 48L38.9334 44.2667Z"></path>
|
|
38
|
-
</svg>
|
|
39
|
-
</button>
|
|
40
|
-
|
|
41
|
-
<button
|
|
42
|
-
class="de-menu de-link-add"
|
|
43
|
-
@click="
|
|
44
|
-
() => {
|
|
45
|
-
isActiveLinkArea = !isActiveLinkArea;
|
|
46
|
-
openLinkArea();
|
|
47
|
-
}
|
|
48
|
-
"
|
|
49
|
-
>
|
|
50
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
51
|
-
<path class="de-path" d="M45.3334 18.6665H34.6667V23.9998H45.3334C49.7334 23.9998 53.3334 27.5998 53.3334 31.9998C53.3334 36.3998 49.7334 39.9998 45.3334 39.9998H34.6667V45.3332H45.3334C52.6934 45.3332 58.6667 39.3598 58.6667 31.9998C58.6667 24.6398 52.6934 18.6665 45.3334 18.6665ZM29.3334 39.9998H18.6667C14.2667 39.9998 10.6667 36.3998 10.6667 31.9998C10.6667 27.5998 14.2667 23.9998 18.6667 23.9998H29.3334V18.6665H18.6667C11.3067 18.6665 5.33337 24.6398 5.33337 31.9998C5.33337 39.3598 11.3067 45.3332 18.6667 45.3332H29.3334V39.9998ZM21.3334 29.3332H42.6667V34.6665H21.3334V29.3332Z"></path>
|
|
52
|
-
</svg>
|
|
53
|
-
</button>
|
|
54
|
-
|
|
55
|
-
<button class="de-menu" @click="removeLink">
|
|
56
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
57
|
-
<path class="de-path" d="M38.3734 29.5065L42.6667 33.7998V29.5065H38.3734ZM45.3334 18.8398H34.6667V23.9065H45.3334C49.8934 23.9065 53.6 27.6131 53.6 32.1731C53.6 35.5598 51.5467 38.4931 48.6134 39.7465L52.3467 43.4798C56.1334 41.1331 58.6667 36.9465 58.6667 32.1731C58.6667 24.8131 52.6934 18.8398 45.3334 18.8398ZM5.33337 11.5598L13.6267 19.8531C8.77337 21.8265 5.33337 26.5998 5.33337 32.1731C5.33337 39.5331 11.3067 45.5065 18.6667 45.5065H29.3334V40.4398H18.6667C14.1067 40.4398 10.4 36.7331 10.4 32.1731C10.4 27.9331 13.6267 24.4398 17.76 23.9865L23.28 29.5065H21.3334V34.8398H28.6134L34.6667 40.8931V45.5065H39.28L49.9734 56.1998L53.7334 52.4398L9.09337 7.7998L5.33337 11.5598Z"></path>
|
|
58
|
-
</svg>
|
|
59
|
-
</button>
|
|
60
|
-
|
|
61
|
-
<label class="de-menu">
|
|
62
|
-
<input type="file" hidden accept=".jpg,.jpeg,.png,.webp,.gif" @change="chooseMediaEvent" />
|
|
63
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
64
|
-
<path d="M50.6667 13.3333V50.6667H13.3333V13.3333H50.6667ZM50.6667 8H13.3333C10.4 8 8 10.4 8 13.3333V50.6667C8 53.6 10.4 56 13.3333 56H50.6667C53.6 56 56 53.6 56 50.6667V13.3333C56 10.4 53.6 8 50.6667 8ZM37.7067 31.6267L29.7067 41.9467L24 35.04L16 45.3333H48L37.7067 31.6267Z"></path>
|
|
65
|
-
</svg>
|
|
66
|
-
</label>
|
|
67
|
-
|
|
68
|
-
<button class="de-menu" @click="setTextAlign('left')">
|
|
69
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
70
|
-
<path class="de-path" d="M40 40H8V45.3333H40V40ZM40 18.6667H8V24H40V18.6667ZM8 34.6667H56V29.3333H8V34.6667ZM8 56H56V50.6667H8V56ZM8 8V13.3333H56V8H8Z"></path>
|
|
71
|
-
</svg>
|
|
72
|
-
</button>
|
|
73
|
-
|
|
74
|
-
<button class="de-menu" @click="setTextAlign('center')">
|
|
75
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
76
|
-
<path class="de-path" d="M18.6667 40V45.3333H45.3333V40H18.6667ZM8 56H56V50.6667H8V56ZM8 34.6667H56V29.3333H8V34.6667ZM18.6667 18.6667V24H45.3333V18.6667H18.6667ZM8 8V13.3333H56V8H8Z"></path>
|
|
77
|
-
</svg>
|
|
78
|
-
</button>
|
|
79
|
-
|
|
80
|
-
<button class="de-menu" @click="setTextAlign('right')">
|
|
81
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
82
|
-
<path class="de-path" d="M8 56H56V50.6667H8V56ZM24 45.3333H56V40H24V45.3333ZM8 34.6667H56V29.3333H8V34.6667ZM24 24H56V18.6667H24V24ZM8 8V13.3333H56V8H8Z"></path>
|
|
83
|
-
</svg>
|
|
84
|
-
</button>
|
|
85
|
-
|
|
86
|
-
<button class="de-menu" @click="setTextAlign('justify')">
|
|
87
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
88
|
-
<path class="de-path" d="M8 56H56V50.6667H8V56ZM8 45.3333H56V40H8V45.3333ZM8 34.6667H56V29.3333H8V34.6667ZM8 24H56V18.6667H8V24ZM8 8V13.3333H56V8H8Z"></path>
|
|
89
|
-
</svg>
|
|
90
|
-
</button>
|
|
91
|
-
|
|
92
|
-
<button class="de-menu" @click="moveBlock('up')">
|
|
93
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
94
|
-
<path d="M9.33333 35.9999C9.33333 29.4666 14.0267 24.0799 20.2133 22.9066L16.24 26.9066L20 30.6666L30.6667 19.9733L20 9.33325L16.24 13.0933L20.4533 17.3066V17.4666C11.2 18.5599 4 26.4533 4 35.9999C4 46.3199 12.3467 54.6666 22.6667 54.6666H30.6667V49.3333H22.6667C15.3067 49.3333 9.33333 43.3599 9.33333 35.9999Z M36 35.9999V54.6666H60V35.9999H36ZM54.6667 49.3333H41.3333V41.3333H54.6667V49.3333Z M60 11.9999H36V30.6666H60V11.9999Z"></path>
|
|
95
|
-
</svg>
|
|
96
|
-
</button>
|
|
97
|
-
|
|
98
|
-
<button class="de-menu" @click="moveBlock('down')">
|
|
99
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
100
|
-
<path d="M9.33333 27.9999C9.33333 34.5333 14.0267 39.9199 20.2133 41.0933L16.24 37.1199L20 33.3333L30.6667 44.0266L20 54.6666L16.24 50.9066L20.4533 46.6933V46.5333C11.2 45.4399 4 37.5466 4 27.9999C4 17.6799 12.3467 9.33325 22.6667 9.33325H30.6667V14.6666H22.6667C15.3067 14.6666 9.33333 20.6399 9.33333 27.9999Z M60 27.9999V9.33325H36V27.9999H60ZM54.6667 22.6666H41.3333V14.6666H54.6667V22.6666Z M60 33.3333H36V51.9999H60V33.3333Z"></path>
|
|
101
|
-
</svg>
|
|
102
|
-
</button>
|
|
103
|
-
|
|
104
|
-
<button class="de-menu" @click="deleteBlock">
|
|
105
|
-
<svg class="de-icon" viewBox="0 0 64 64">
|
|
106
|
-
<path class="de-path --red" fill-rule="evenodd" clip-rule="evenodd" d="M42.6667 24V50.6667H21.3334V24H42.6667ZM38.6667 8H25.3334L22.6667 10.6667H13.3334V16H50.6667V10.6667H41.3334L38.6667 8ZM48 18.6667H16V50.6667C16 53.6 18.4 56 21.3334 56H42.6667C45.6 56 48 53.6 48 50.6667V18.6667Z"></path>
|
|
107
|
-
</svg>
|
|
108
|
-
</button>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<div class="de-block-menu-area" :class="{ '--active': isActiveAddBlockMenu }">
|
|
112
|
-
<div class="de-list">
|
|
113
|
-
<button class="de-add-block" @click="addBlock('text')">Text</button>
|
|
114
|
-
<button class="de-add-block" @click="addBlock('heading1')">Heading-1</button>
|
|
115
|
-
<button class="de-add-block" @click="addBlock('heading2')">Heading-2</button>
|
|
116
|
-
<button class="de-add-block" @click="addBlock('heading3')">Heading-3</button>
|
|
117
|
-
<button class="de-add-block" @click="addBlock('ul')">Unodered List</button>
|
|
118
|
-
<button class="de-add-block" @click="addBlock('ol')">Odered List</button>
|
|
119
|
-
<button class="de-add-block" @click="addBlock('code')">Code Block</button>
|
|
120
|
-
<!-- <button class="de-add-block" @click="addBlock('table')">Table Block</button> -->
|
|
121
|
-
<!-- <button class="de-add-block" @click="addBlock('video')">Video</button> youtube | vimeo -->
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
|
|
125
|
-
<div class="de-link-exit-area" :class="{ '--active': isActiveLinkArea }">
|
|
126
|
-
<div class="de-btn-area">
|
|
127
|
-
<button class="de-btn" :class="{ '--active': activeLinkTabType === 'url' }" @click="openLinkArea"> Text </button>
|
|
128
|
-
<button class="de-btn" :class="{ '--active': activeLinkTabType === 'heading' }" @click="listUpHeading">Heading</button>
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
<div v-if="activeLinkTabType === 'url'" class="de-link-text-area">
|
|
132
|
-
<input v-model="anchorTagValue" class="de-input" :class="{ '--red': anchorValueError }" type="url" ref="$linkInput" />
|
|
133
|
-
<button class="de-btn" @click="setLink">Add</button>
|
|
134
|
-
</div>
|
|
135
|
-
|
|
136
|
-
<div v-if="activeLinkTabType === 'heading'" class="de-link-heading-area">
|
|
137
|
-
<button v-for="item in anchorHeadingList" class="de-btn" @click="setHeadingLink(item.id)">{{ item.name }}</button>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
|
|
142
|
-
<div v-if="editorStore.$currentBlock !== null" class="de-control-bar" :class="{ '--active': editorStore.controlBar.active === true }" :style="{ top: `${editorStore.controlBar.y}px`, left: `${editorStore.controlBar.x}px` }" ref="$controlBar">
|
|
143
|
-
<div v-if="['code'].includes(curruntType) === true" class="de-col">
|
|
144
|
-
<p class="de-name">Theme :</p>
|
|
145
|
-
<select class="de-selector" v-model="codeBlockTheme" @change="codeBlockThemeChangeEvent">
|
|
146
|
-
<option v-for="(item, i) in _getCodeBlockTheme()" :value="item.code" :key="`codeBlockTheme-${i}`">{{ item.text }}</option>
|
|
147
|
-
</select>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div v-if="['code'].includes(curruntType) === true" class="de-col">
|
|
151
|
-
<p class="de-name">Language :</p>
|
|
152
|
-
<select class="de-selector" v-model="codeblockLanguage" @change="codeblockLanguageChangeEvent">
|
|
153
|
-
<option v-for="(item, i) in _getCodeBlockLanguage()" :value="item.code" :key="`codeBlockLanuage-${i}`">{{ item.text }}</option>
|
|
154
|
-
</select>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<div v-if="['list'].includes(curruntType) === true" class="de-col">
|
|
158
|
-
<p class="de-name">List Style :</p>
|
|
159
|
-
<select class="de-selector" v-model="listBlockStyle" @change="listBlockStyleChangeEvent">
|
|
160
|
-
<template v-if="editorStore.$currentBlock.tagName === 'UL'">
|
|
161
|
-
<option value="disc">Disc</option>
|
|
162
|
-
<option value="square">Square</option>
|
|
163
|
-
</template>
|
|
164
|
-
|
|
165
|
-
<template v-else>
|
|
166
|
-
<option value="decimal">Decimal</option>
|
|
167
|
-
<option value="lower-alpha">Lower-Alpha</option>
|
|
168
|
-
<option value="upper-alpha">Upper-Alpha</option>
|
|
169
|
-
<option value="lower-roman">Lower-Roman</option>
|
|
170
|
-
<option value="upper-roman">Upper-Roman</option>
|
|
171
|
-
</template>
|
|
172
|
-
</select>
|
|
173
|
-
</div>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
<div class="de-body" ref="$content" @keydown="contentKeyboardEvent" @mouseup="updateCursorData" @mousedown="resizeEventStart" @touchstart="resizeEventStart" @paste="contentPasteEvent">
|
|
177
|
-
<p class="de-block de-text-block" contenteditable="true"></p>
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
2
|
+
<component :is="mainStrucutre()"></component>
|
|
180
3
|
</template>
|
|
181
4
|
|
|
182
5
|
<script setup lang="ts">
|
|
183
|
-
import { ref, onMounted,
|
|
184
|
-
import {
|
|
185
|
-
import {
|
|
186
|
-
import {
|
|
187
|
-
import {
|
|
188
|
-
import {
|
|
189
|
-
import { _setNodeStyle, _setTextAlign, _setAnchorTag, _unsetAnchorTag, _getAnchorTagValue } from "../utils/style";
|
|
190
|
-
import { _setCursor, _setCursorData, _clenupCursor } from "../utils/cursor";
|
|
191
|
-
import { _getContentData, _setContentData } from "../utils/convertor";
|
|
192
|
-
import { _addBlockToContent } from "../utils/content";
|
|
6
|
+
import { ref, h, onMounted, onBeforeUnmount } from "vue";
|
|
7
|
+
import { _getBodyVNodeStructure, _getMenuBarVNodeStructure, _getControlbarVNodeStructure } from "../utils/layout";
|
|
8
|
+
import { _eidtorMountEvent, _eidtorUnmountEvent, _editorMousemoveEvent, _editorMouseupEvent, _editorMouseleaveEvent, _editorTouchmoveEvent, _editorTouchendEvent, _checkOthersideClick, _parentWrapScollEvent, _editorContextMenuEvent, _windowResizeEvent } from "../utils/event";
|
|
9
|
+
import { _addBlock } from "../utils/node";
|
|
10
|
+
import { _setDecoration, _setTextAlign } from "../utils/style";
|
|
11
|
+
import type { VNode } from "vue";
|
|
193
12
|
import "../type.d.ts";
|
|
194
13
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
default: () => "",
|
|
205
|
-
},
|
|
14
|
+
interface DEOption {
|
|
15
|
+
modelValue: DEContentData;
|
|
16
|
+
useMenuBar?: boolean;
|
|
17
|
+
imageHostURL?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const props = withDefaults(defineProps<DEOption>(), {
|
|
21
|
+
useMenuBar: true,
|
|
22
|
+
imageHostURL: "",
|
|
206
23
|
});
|
|
207
24
|
const emit = defineEmits<{
|
|
208
|
-
(e: "
|
|
25
|
+
(e: "update:modelValue", data: DEContentData): void;
|
|
26
|
+
(e: "uploadImageEvent", file: File): void;
|
|
209
27
|
}>();
|
|
210
|
-
const editorStore =
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
28
|
+
const editorStore = ref<DragonEditorStore>({
|
|
29
|
+
cursorData: null,
|
|
30
|
+
message: {
|
|
31
|
+
linkTextNoStyle: "Link text can't set any style.",
|
|
32
|
+
},
|
|
33
|
+
controlBar: {
|
|
34
|
+
active: false,
|
|
35
|
+
x: 0,
|
|
36
|
+
y: 0,
|
|
37
|
+
$element: null,
|
|
38
|
+
},
|
|
39
|
+
useMenuBar: props.useMenuBar,
|
|
40
|
+
imageHostURL: props.imageHostURL,
|
|
41
|
+
firstData: props.modelValue,
|
|
42
|
+
menuBarTop: 0,
|
|
43
|
+
activeStatus: {
|
|
44
|
+
addBlockMenu: false,
|
|
45
|
+
anchorInputArea: false,
|
|
46
|
+
imageResizeEvent: false,
|
|
47
|
+
},
|
|
48
|
+
eventStatus: {
|
|
49
|
+
preComposing: false,
|
|
50
|
+
imageResizeEventStartX: 0,
|
|
51
|
+
imageResizeEventType: "left",
|
|
52
|
+
imageResizeEventEndX: 0,
|
|
53
|
+
imageResizeCurrentWidth: 0,
|
|
54
|
+
keyboardEnterCount: 0,
|
|
55
|
+
},
|
|
56
|
+
controlStatus: {
|
|
57
|
+
isMobile: false,
|
|
58
|
+
currentBlockType: "text",
|
|
59
|
+
codeBlockTheme: "github",
|
|
60
|
+
codeBlockLang: "text",
|
|
61
|
+
listBlockStyle: "disc",
|
|
62
|
+
anchorTabType: "url",
|
|
63
|
+
anchorHeadingList: [],
|
|
64
|
+
anchorHref: "",
|
|
65
|
+
anchorValidation: false,
|
|
66
|
+
previousCorsorData: null,
|
|
67
|
+
$anchorInput: null,
|
|
68
|
+
$currentBlock: null,
|
|
69
|
+
},
|
|
70
|
+
codeBlockTheme: [
|
|
71
|
+
{
|
|
72
|
+
text: "GitHub",
|
|
73
|
+
code: "github",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
text: "GitHub Dark Dimmed",
|
|
77
|
+
code: "github-dark-dimmed",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
listUlType: [
|
|
81
|
+
{
|
|
82
|
+
text: "Disc",
|
|
83
|
+
code: "disc",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
text: "Square",
|
|
87
|
+
code: "square",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
listOlType: [
|
|
91
|
+
{
|
|
92
|
+
text: "Decimal",
|
|
93
|
+
code: "decimal",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
text: "Lower-Alpha",
|
|
97
|
+
code: "lower-alpha",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
text: "Upper-Alpha",
|
|
101
|
+
code: "upper-alpha",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
text: "Lower-Roman",
|
|
105
|
+
code: "lower-roman",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
text: "Upper-Roman",
|
|
109
|
+
code: "upper-roman",
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
$editor: null,
|
|
113
|
+
$body: null,
|
|
114
|
+
$controlBar: null,
|
|
115
|
+
$parentWrap: null,
|
|
116
|
+
emit: emit,
|
|
117
|
+
windowClickEvent: function (event: MouseEvent) {
|
|
118
|
+
_checkOthersideClick(event, editorStore);
|
|
119
|
+
},
|
|
120
|
+
windowResizeEvent: function (event: Event) {
|
|
121
|
+
_windowResizeEvent(event, editorStore);
|
|
122
|
+
},
|
|
123
|
+
windowMouseUpEvent: function (event: MouseEvent) {
|
|
124
|
+
_editorMouseupEvent(event, editorStore);
|
|
125
|
+
},
|
|
126
|
+
parentWrapScollEvent: function (event: Event) {
|
|
127
|
+
_parentWrapScollEvent(event, editorStore);
|
|
128
|
+
},
|
|
129
|
+
});
|
|
250
130
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const $block = (e.target as HTMLElement).closest(".de-block");
|
|
131
|
+
function mainStrucutre(): VNode {
|
|
132
|
+
const childList: VNode[] = [];
|
|
254
133
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
134
|
+
if (editorStore.value.useMenuBar === true) {
|
|
135
|
+
childList.push(_getMenuBarVNodeStructure(editorStore));
|
|
258
136
|
}
|
|
259
137
|
|
|
260
|
-
|
|
261
|
-
anchorTagValueUpdate();
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 컨트롤 바 상태 업데이트
|
|
265
|
-
function controlBarStatusUpdate() {
|
|
266
|
-
if (editorStore.$currentBlock !== null) {
|
|
267
|
-
const { type } = _getBlockType(editorStore.$currentBlock);
|
|
268
|
-
const activeList = ["code", "list"];
|
|
138
|
+
childList.push(_getBodyVNodeStructure(editorStore));
|
|
269
139
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (activeList.includes(curruntType.value) === true) {
|
|
273
|
-
editorStore.controlBarActive();
|
|
274
|
-
|
|
275
|
-
switch (type) {
|
|
276
|
-
case "code":
|
|
277
|
-
_updateCodeBlockStyle(editorStore, codeBlockTheme, codeblockLanguage);
|
|
278
|
-
break;
|
|
279
|
-
case "list":
|
|
280
|
-
_updateListBlockStyle(editorStore, listBlockStyle);
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
} else {
|
|
284
|
-
editorStore.controlBarDeactive();
|
|
285
|
-
}
|
|
140
|
+
if (editorStore.value.controlBar.active === true) {
|
|
141
|
+
childList.push(_getControlbarVNodeStructure(editorStore));
|
|
286
142
|
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// 사이즈 조정 이벤트 시작
|
|
290
|
-
function resizeEventStart(event: Event) {
|
|
291
|
-
const $target = event.target as HTMLElement;
|
|
292
|
-
|
|
293
|
-
if ($target !== null) {
|
|
294
|
-
const $block = $target.closest(".de-block");
|
|
295
143
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
144
|
+
return h(
|
|
145
|
+
"div",
|
|
146
|
+
{
|
|
147
|
+
class: ["dragon-editor", "js-dragon-editor", { "--has-menu": editorStore.value.useMenuBar === true }, { "--mobile": editorStore.value.controlStatus.isMobile === true }],
|
|
148
|
+
onMousemove: (event: MouseEvent) => _editorMousemoveEvent(event, editorStore),
|
|
149
|
+
onMouseup: (event: MouseEvent) => _editorMouseupEvent(event, editorStore),
|
|
150
|
+
onMouseleave: (event: MouseEvent) => _editorMouseleaveEvent(event, editorStore),
|
|
151
|
+
onTouchmove: (event: TouchEvent) => _editorTouchmoveEvent(event, editorStore),
|
|
152
|
+
onTouchend: (event: TouchEvent) => _editorTouchendEvent(event, editorStore),
|
|
153
|
+
onContextmenu: (event: MouseEvent) => _editorContextMenuEvent(event, editorStore),
|
|
154
|
+
},
|
|
155
|
+
childList
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 외부용 블럭 추가 함수
|
|
160
|
+
function addBlock(data: DEBlockData): void {
|
|
161
|
+
let type: DEBlockMenutype = "text";
|
|
162
|
+
|
|
163
|
+
switch (data.type) {
|
|
164
|
+
case "heading":
|
|
165
|
+
if (data.level === 1) {
|
|
166
|
+
type = "heading1";
|
|
167
|
+
} else if (data.level === 2) {
|
|
168
|
+
type = "heading2";
|
|
308
169
|
} else {
|
|
309
|
-
|
|
170
|
+
type = "heading3";
|
|
310
171
|
}
|
|
311
|
-
|
|
312
|
-
resizeEndX = resizeStartX;
|
|
313
|
-
|
|
314
|
-
const $imgArea = (editorStore.$currentBlock as HTMLElement).querySelector(".de-image-area") as HTMLDivElement;
|
|
315
|
-
resizeCurruntWidth = parseInt($imgArea.dataset["maxwidth"] ?? "25");
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// 사이즈 조정 이벤트
|
|
321
|
-
function resizeEvent(event: Event) {
|
|
322
|
-
if (resizeEventActive === true) {
|
|
323
|
-
const $imgArea = (editorStore.$currentBlock as HTMLElement).querySelector(".de-image-area") as HTMLDivElement;
|
|
324
|
-
const contentWidth = (editorStore.$content?.offsetWidth ?? 0) / 2;
|
|
325
|
-
let gap: number = 0;
|
|
326
|
-
|
|
327
|
-
if (event.type === "touchmove") {
|
|
328
|
-
resizeEndX = (event as TouchEvent).touches[0].clientX;
|
|
329
|
-
} else {
|
|
330
|
-
resizeEndX = (event as MouseEvent).clientX;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (resizeType === "right") {
|
|
334
|
-
gap = Math.floor(resizeStartX - resizeEndX);
|
|
335
|
-
} else {
|
|
336
|
-
gap = Math.floor(resizeEndX - resizeStartX);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const percent = (100 / contentWidth) * gap;
|
|
340
|
-
let value = Math.floor(resizeCurruntWidth - percent);
|
|
341
|
-
|
|
342
|
-
if (value < 25) {
|
|
343
|
-
value = 25;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (value > 100) {
|
|
347
|
-
value = 100;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
$imgArea.dataset["maxwidth"] = String(value);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// 사이즈 조정 이벤트 종료
|
|
355
|
-
function resizeEventEnd() {
|
|
356
|
-
if (resizeEventActive === true) {
|
|
357
|
-
resizeEventActive = false;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// 메뉴 외부 클릭시 닫기
|
|
362
|
-
function checkOthersideClick(event: MouseEvent) {
|
|
363
|
-
if (event.target !== null) {
|
|
364
|
-
const $controlBar = (event.target as HTMLElement).closest(".de-menu-bar");
|
|
365
|
-
const $btnMenu = (event.target as HTMLElement).closest(".de-menu-add");
|
|
366
|
-
const $menuArea = (event.target as HTMLElement).closest(".de-block-menu-area");
|
|
367
|
-
const $btnLink = (event.target as HTMLElement).closest(".de-link-add");
|
|
368
|
-
const $linkArea = (event.target as HTMLElement).closest(".de-link-exit-area");
|
|
369
|
-
let closeMenu: boolean = false;
|
|
370
|
-
let closeLink: boolean = false;
|
|
371
|
-
|
|
372
|
-
if ($controlBar === null) {
|
|
373
|
-
closeMenu = true;
|
|
374
|
-
closeLink = true;
|
|
375
|
-
} else {
|
|
376
|
-
if ($btnMenu === null && $menuArea === null) {
|
|
377
|
-
closeMenu = true;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
if ($btnLink === null && $linkArea === null) {
|
|
381
|
-
closeLink = true;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (closeMenu === true) {
|
|
386
|
-
isActiveAddBlockMenu.value = false;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (closeLink === true) {
|
|
390
|
-
isActiveLinkArea.value = false;
|
|
391
|
-
anchorTagValue.value = "";
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// 블럭 삭제
|
|
397
|
-
function deleteBlock() {
|
|
398
|
-
if (editorStore.$currentBlock !== null) {
|
|
399
|
-
const childCount: number = editorStore.$content?.childElementCount ?? 1;
|
|
400
|
-
|
|
401
|
-
editorStore.$currentBlock.remove();
|
|
402
|
-
editorStore.setCurrentBlock(null);
|
|
403
|
-
|
|
404
|
-
if (childCount < 2) {
|
|
405
|
-
// 모든 엘리먼트를 지우려는 경우
|
|
406
|
-
const $block = _createTextBlock();
|
|
407
|
-
|
|
408
|
-
editorStore.$content?.insertAdjacentElement("beforeend", $block);
|
|
409
|
-
_setCursor($block, 0);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// 부모 요소 스크롤 이벤트 발생시 컨트롤 바 고정
|
|
415
|
-
function parentWrapScollEvent() {
|
|
416
|
-
if (props.useMenuBar === true && editorStore.$parentWrap !== null && editorStore.$editor !== null) {
|
|
417
|
-
// 메뉴바를 사용하는 경우만
|
|
418
|
-
|
|
419
|
-
const editorReac = editorStore.$editor.getBoundingClientRect();
|
|
420
|
-
let scrollY: number = 0;
|
|
421
|
-
|
|
422
|
-
if (editorStore.$parentWrap.constructor.name === "Window") {
|
|
423
|
-
scrollY = (editorStore.$parentWrap as Window).scrollY;
|
|
424
|
-
} else {
|
|
425
|
-
scrollY = (editorStore.$parentWrap as HTMLElement).scrollTop;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
let realElementY = editorReac.y + scrollY;
|
|
429
|
-
|
|
430
|
-
if (editorStore.$parentWrap.constructor.name !== "Window") {
|
|
431
|
-
const parentRect = (editorStore.$parentWrap as HTMLElement).getBoundingClientRect();
|
|
432
|
-
|
|
433
|
-
realElementY -= parentRect.y;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
let value: number = 0;
|
|
437
|
-
|
|
438
|
-
if (scrollY > realElementY) {
|
|
439
|
-
value = scrollY - realElementY - 1;
|
|
440
|
-
} else {
|
|
441
|
-
value = 0;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (value > editorReac.height - 39) {
|
|
445
|
-
value = editorReac.height - 39;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
menuBarTop.value = Math.floor(value);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// 붙여넣기 이벤트
|
|
453
|
-
function contentPasteEvent(event: ClipboardEvent) {
|
|
454
|
-
_pasteEvent(event, editorStore, emit);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
function anchorTagValueUpdate() {
|
|
458
|
-
// 다른 이벤트 순서에 의한 딜레이
|
|
459
|
-
setTimeout(() => {
|
|
460
|
-
anchorTagValue.value = _getAnchorTagValue(editorStore);
|
|
461
|
-
}, 500);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* 이벤트 관련 영역 종료
|
|
466
|
-
*/
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* 컨트롤 바 이벤트 관련 영역 시작
|
|
470
|
-
*/
|
|
471
|
-
|
|
472
|
-
// 코드 블럭 테마 적용
|
|
473
|
-
function codeBlockThemeChangeEvent() {
|
|
474
|
-
_setCodeBlockTheme(editorStore, codeBlockTheme.value);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// 코드 블럭 언어 적용
|
|
478
|
-
function codeblockLanguageChangeEvent() {
|
|
479
|
-
_setCodeBlockLanguage(editorStore, codeblockLanguage.value);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// 리스트 스타일 적용
|
|
483
|
-
function listBlockStyleChangeEvent() {
|
|
484
|
-
_setListBlockStyle(editorStore, listBlockStyle.value);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/**
|
|
488
|
-
* 컨트롤 바 이벤트 관련 영역 종료
|
|
489
|
-
*/
|
|
490
|
-
|
|
491
|
-
/**
|
|
492
|
-
* 메뉴 이벤트 관련 영역
|
|
493
|
-
*/
|
|
494
|
-
function addBlock(type: string) {
|
|
495
|
-
isActiveAddBlockMenu.value = false;
|
|
496
|
-
|
|
497
|
-
let blockStructure: HTMLElement | null = null;
|
|
498
|
-
|
|
499
|
-
switch (type) {
|
|
500
|
-
case "text":
|
|
501
|
-
blockStructure = _createTextBlock();
|
|
502
172
|
break;
|
|
503
|
-
case "heading1":
|
|
504
|
-
case "heading2":
|
|
505
|
-
case "heading3":
|
|
506
|
-
const level: number = parseInt(type.replace("heading", ""));
|
|
507
|
-
|
|
508
|
-
blockStructure = _createHeadingBlock({
|
|
509
|
-
type: "heading",
|
|
510
|
-
classList: [],
|
|
511
|
-
id: "",
|
|
512
|
-
level: level,
|
|
513
|
-
textContent: "",
|
|
514
|
-
});
|
|
515
|
-
break;
|
|
516
|
-
case "ul":
|
|
517
|
-
case "ol":
|
|
518
|
-
blockStructure = _createListBlock({
|
|
519
|
-
type: "list",
|
|
520
|
-
element: type,
|
|
521
|
-
style: type === "ul" ? "disc" : "decimal",
|
|
522
|
-
child: [
|
|
523
|
-
{
|
|
524
|
-
classList: [],
|
|
525
|
-
textContent: "",
|
|
526
|
-
},
|
|
527
|
-
],
|
|
528
|
-
});
|
|
529
|
-
break;
|
|
530
|
-
case "table":
|
|
531
|
-
// TODO : table block
|
|
532
|
-
break;
|
|
533
|
-
case "code":
|
|
534
|
-
blockStructure = _createCodeBlock({
|
|
535
|
-
type: "code",
|
|
536
|
-
theme: "github",
|
|
537
|
-
filename: "",
|
|
538
|
-
language: "Plain Text",
|
|
539
|
-
textContent: "",
|
|
540
|
-
});
|
|
541
|
-
break;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (blockStructure !== null) {
|
|
545
|
-
_addBlockToContent(blockStructure, editorStore);
|
|
546
|
-
|
|
547
|
-
switch (type) {
|
|
548
|
-
case "ul":
|
|
549
|
-
case "ol":
|
|
550
|
-
(blockStructure.childNodes[0] as HTMLElement).focus();
|
|
551
|
-
break;
|
|
552
|
-
case "codeblock":
|
|
553
|
-
blockStructure.querySelector("code")?.focus();
|
|
554
|
-
break;
|
|
555
|
-
default:
|
|
556
|
-
blockStructure.focus();
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
editorStore.setCurrentBlock(blockStructure as HTMLElement);
|
|
560
|
-
controlBarStatusUpdate();
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
function addCustomBlock(HTML: string, classList: string[] = []) {
|
|
565
|
-
const blockStructure = _createCustomBlock({
|
|
566
|
-
type: "custom",
|
|
567
|
-
classList: classList,
|
|
568
|
-
textContent: HTML,
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
_addBlockToContent(blockStructure, editorStore);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
function addImageBlock(data: DEImage) {
|
|
575
|
-
if (props.imageHostURL !== "") {
|
|
576
|
-
data.src = props.imageHostURL + data.src;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
const blockStructure = _createImageBlock({
|
|
580
|
-
...data,
|
|
581
|
-
type: "image",
|
|
582
|
-
maxWidth: 100,
|
|
583
|
-
classList: [],
|
|
584
|
-
} as DEImageBlock);
|
|
585
|
-
|
|
586
|
-
_addBlockToContent(blockStructure, editorStore);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
function setDecoration(type: DEDecoration) {
|
|
590
|
-
_setNodeStyle(`de-${type}`, editorStore);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
function setTextAlign(type: DETextalign) {
|
|
594
|
-
_setTextAlign(type, editorStore);
|
|
595
|
-
}
|
|
596
173
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
} else {
|
|
601
|
-
console.error("[DragonEditor] Con't find content Element.");
|
|
602
|
-
return [];
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
function setContentData(data: DEContentData) {
|
|
607
|
-
_setContentData(data, editorStore, props.imageHostURL);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
function moveBlock(type: "up" | "down") {
|
|
611
|
-
if (editorStore.$currentBlock !== null) {
|
|
612
|
-
let $target: Element | null;
|
|
613
|
-
|
|
614
|
-
if (type === "up") {
|
|
615
|
-
$target = editorStore.$currentBlock.previousElementSibling;
|
|
616
|
-
} else {
|
|
617
|
-
$target = editorStore.$currentBlock.nextElementSibling;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
if ($target !== null) {
|
|
621
|
-
($target as HTMLElement).insertAdjacentHTML(type === "up" ? "beforebegin" : "afterend", editorStore.$currentBlock.outerHTML);
|
|
622
|
-
editorStore.$currentBlock.remove();
|
|
623
|
-
|
|
624
|
-
if (type === "up") {
|
|
625
|
-
editorStore.setCurrentBlock(($target as HTMLElement).previousElementSibling as HTMLElement | null);
|
|
174
|
+
case "list":
|
|
175
|
+
if (data.element === "ol") {
|
|
176
|
+
type = "ol";
|
|
626
177
|
} else {
|
|
627
|
-
|
|
178
|
+
type = "ul";
|
|
628
179
|
}
|
|
629
|
-
|
|
180
|
+
break;
|
|
630
181
|
}
|
|
631
|
-
}
|
|
632
182
|
|
|
633
|
-
|
|
634
|
-
activeLinkTabType.value = "url";
|
|
635
|
-
anchorValueError.value = false;
|
|
183
|
+
_addBlock(type, editorStore, data);
|
|
636
184
|
}
|
|
637
185
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
emit("uploadImageEvent", file);
|
|
643
|
-
$target.value = "";
|
|
186
|
+
// 외부용 스타일 적용 함수
|
|
187
|
+
function setDecoration(style: DEDecoration): void {
|
|
188
|
+
_setDecoration(`de-${style}`, editorStore);
|
|
644
189
|
}
|
|
645
190
|
|
|
646
|
-
//
|
|
647
|
-
function
|
|
648
|
-
|
|
649
|
-
_setAnchorTag(anchorTagValue.value, true, editorStore);
|
|
650
|
-
isActiveLinkArea.value = false;
|
|
651
|
-
anchorValueError.value = false;
|
|
652
|
-
anchorTagValue.value = "";
|
|
653
|
-
} else {
|
|
654
|
-
anchorValueError.value = true;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
function setHeadingLink(id: string) {
|
|
659
|
-
_setAnchorTag(id, false, editorStore);
|
|
660
|
-
isActiveLinkArea.value = false;
|
|
661
|
-
anchorValueError.value = false;
|
|
662
|
-
anchorTagValue.value = "";
|
|
191
|
+
// 외부용 정렬 함수
|
|
192
|
+
function setAlign(align: DETextalign): void {
|
|
193
|
+
_setTextAlign(align, editorStore);
|
|
663
194
|
}
|
|
664
195
|
|
|
665
|
-
// 헤딩 리스트 업데이트
|
|
666
|
-
function listUpHeading() {
|
|
667
|
-
activeLinkTabType.value = "heading";
|
|
668
|
-
|
|
669
|
-
if (editorStore.$content !== null) {
|
|
670
|
-
const $blockList = editorStore.$content.querySelectorAll(".de-heading-block");
|
|
671
|
-
let headingList: DEHeadingItem[] = [];
|
|
672
|
-
|
|
673
|
-
$blockList.forEach(($headingTag) => {
|
|
674
|
-
if ($headingTag.textContent !== null) {
|
|
675
|
-
headingList.push({
|
|
676
|
-
name: $headingTag.textContent,
|
|
677
|
-
id: $headingTag.id,
|
|
678
|
-
});
|
|
679
|
-
}
|
|
680
|
-
});
|
|
681
|
-
|
|
682
|
-
anchorHeadingList.value = headingList;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
function removeLink() {
|
|
687
|
-
_unsetAnchorTag(editorStore);
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
/**
|
|
691
|
-
* 메뉴 이벤트 관련 영역 종료
|
|
692
|
-
*/
|
|
693
|
-
|
|
694
196
|
onMounted(() => {
|
|
695
|
-
|
|
696
|
-
editorStore.setWrapElement($editor.value);
|
|
697
|
-
editorStore.setParentWrapElement(_findScrollingElement($editor.value));
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
if ($content.value !== undefined) {
|
|
701
|
-
editorStore.setContentElement($content.value);
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
if ($controlBar.value !== undefined) {
|
|
705
|
-
editorStore.setContrulBar($controlBar.value);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
window.addEventListener("click", checkOthersideClick, true);
|
|
709
|
-
editorStore.$parentWrap?.addEventListener("scroll", parentWrapScollEvent, true);
|
|
197
|
+
_eidtorMountEvent(editorStore);
|
|
710
198
|
});
|
|
711
199
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
editorStore.$parentWrap?.removeEventListener("scroll", parentWrapScollEvent, true);
|
|
200
|
+
onBeforeUnmount(() => {
|
|
201
|
+
_eidtorUnmountEvent(editorStore);
|
|
715
202
|
});
|
|
716
203
|
|
|
717
204
|
defineExpose({
|
|
718
205
|
addBlock,
|
|
719
|
-
addImageBlock,
|
|
720
206
|
setDecoration,
|
|
721
|
-
|
|
722
|
-
getContentData,
|
|
723
|
-
setContentData,
|
|
724
|
-
addCustomBlock,
|
|
207
|
+
setAlign,
|
|
725
208
|
});
|
|
726
209
|
</script>
|
|
727
210
|
|
|
@@ -729,6 +212,7 @@ defineExpose({
|
|
|
729
212
|
@charset "UTF-8";
|
|
730
213
|
.dragon-editor,
|
|
731
214
|
.dragon-editor-viewer {
|
|
215
|
+
--radius-default: 4px;
|
|
732
216
|
/**
|
|
733
217
|
* Reset style start
|
|
734
218
|
*/
|
|
@@ -815,6 +299,7 @@ defineExpose({
|
|
|
815
299
|
padding: 0;
|
|
816
300
|
border-radius: 0;
|
|
817
301
|
outline: 0;
|
|
302
|
+
font-size: inherit;
|
|
818
303
|
vertical-align: middle;
|
|
819
304
|
}
|
|
820
305
|
.dragon-editor a,
|
|
@@ -829,6 +314,7 @@ defineExpose({
|
|
|
829
314
|
.dragon-editor-viewer input[type=reset] {
|
|
830
315
|
border: 0;
|
|
831
316
|
background: transparent;
|
|
317
|
+
font-size: inherit;
|
|
832
318
|
cursor: pointer;
|
|
833
319
|
}
|
|
834
320
|
.dragon-editor img,
|
|
@@ -856,6 +342,26 @@ defineExpose({
|
|
|
856
342
|
.dragon-editor-viewer .de-block[data-depth="5"] {
|
|
857
343
|
padding-left: 150px;
|
|
858
344
|
}
|
|
345
|
+
.dragon-editor .de-block.de-list-block[data-depth="1"],
|
|
346
|
+
.dragon-editor-viewer .de-block.de-list-block[data-depth="1"] {
|
|
347
|
+
padding-left: 54px;
|
|
348
|
+
}
|
|
349
|
+
.dragon-editor .de-block.de-list-block[data-depth="2"],
|
|
350
|
+
.dragon-editor-viewer .de-block.de-list-block[data-depth="2"] {
|
|
351
|
+
padding-left: 84px;
|
|
352
|
+
}
|
|
353
|
+
.dragon-editor .de-block.de-list-block[data-depth="3"],
|
|
354
|
+
.dragon-editor-viewer .de-block.de-list-block[data-depth="3"] {
|
|
355
|
+
padding-left: 114px;
|
|
356
|
+
}
|
|
357
|
+
.dragon-editor .de-block.de-list-block[data-depth="4"],
|
|
358
|
+
.dragon-editor-viewer .de-block.de-list-block[data-depth="4"] {
|
|
359
|
+
padding-left: 144px;
|
|
360
|
+
}
|
|
361
|
+
.dragon-editor .de-block.de-list-block[data-depth="5"],
|
|
362
|
+
.dragon-editor-viewer .de-block.de-list-block[data-depth="5"] {
|
|
363
|
+
padding-left: 174px;
|
|
364
|
+
}
|
|
859
365
|
|
|
860
366
|
/**
|
|
861
367
|
* 노드 스타일
|
|
@@ -863,14 +369,19 @@ defineExpose({
|
|
|
863
369
|
.dragon-editor {
|
|
864
370
|
position: relative;
|
|
865
371
|
border: 1px solid #ccc;
|
|
372
|
+
border-radius: var(--radius-default);
|
|
373
|
+
}
|
|
374
|
+
.dragon-editor.--has-menu {
|
|
375
|
+
padding-top: 35px;
|
|
866
376
|
}
|
|
867
|
-
.dragon-editor.--
|
|
868
|
-
|
|
377
|
+
.dragon-editor.--mobile .de-menu-bar .de-menu-wrap {
|
|
378
|
+
overflow-x: auto;
|
|
869
379
|
}
|
|
870
380
|
.dragon-editor .de-body {
|
|
871
381
|
display: flex;
|
|
872
382
|
flex-direction: column;
|
|
873
383
|
gap: 4px;
|
|
384
|
+
min-height: 500px;
|
|
874
385
|
padding: 20px;
|
|
875
386
|
line-height: 1.6;
|
|
876
387
|
}
|
|
@@ -879,43 +390,58 @@ defineExpose({
|
|
|
879
390
|
top: 0;
|
|
880
391
|
left: 0;
|
|
881
392
|
right: 0;
|
|
882
|
-
height:
|
|
393
|
+
height: 34px;
|
|
883
394
|
background: #fff;
|
|
884
395
|
border-bottom: 1px solid #ccc;
|
|
396
|
+
border-radius: var(--radius-default) var(--radius-default) 0 0;
|
|
885
397
|
z-index: 10;
|
|
886
398
|
}
|
|
887
399
|
.dragon-editor .de-menu-bar .de-menu-wrap {
|
|
888
400
|
display: flex;
|
|
889
|
-
|
|
401
|
+
}
|
|
402
|
+
.dragon-editor .de-menu-bar .de-col {
|
|
403
|
+
display: flex;
|
|
404
|
+
position: relative;
|
|
405
|
+
border-right: 1px solid #ccc;
|
|
406
|
+
}
|
|
407
|
+
.dragon-editor .de-menu-bar .de-col:last-child {
|
|
408
|
+
border-right: 0;
|
|
890
409
|
}
|
|
891
410
|
.dragon-editor .de-menu-bar .de-menu {
|
|
892
411
|
display: flex;
|
|
893
412
|
justify-content: center;
|
|
894
413
|
align-items: center;
|
|
895
|
-
min-width:
|
|
896
|
-
height:
|
|
897
|
-
border-right: 1px solid #ccc;
|
|
898
|
-
box-sizing: border-box;
|
|
414
|
+
min-width: 34px;
|
|
415
|
+
height: 34px;
|
|
899
416
|
cursor: pointer;
|
|
900
417
|
}
|
|
418
|
+
.dragon-editor .de-menu-bar .de-menu.--disabled .de-path {
|
|
419
|
+
fill: #ccc;
|
|
420
|
+
}
|
|
901
421
|
.dragon-editor .de-menu-bar .de-menu .de-icon {
|
|
902
|
-
width:
|
|
903
|
-
height:
|
|
422
|
+
width: 16px;
|
|
423
|
+
height: 16px;
|
|
904
424
|
}
|
|
905
425
|
.dragon-editor .de-menu-bar .de-menu.--lastchild {
|
|
906
426
|
border-right: 0;
|
|
907
427
|
}
|
|
428
|
+
.dragon-editor .de-menu-bar .de-menu .de-path {
|
|
429
|
+
fill: #333;
|
|
430
|
+
}
|
|
908
431
|
.dragon-editor .de-menu-bar .de-menu .de-path.--red {
|
|
909
432
|
fill: #dd0000;
|
|
910
433
|
}
|
|
911
434
|
.dragon-editor .de-menu-bar .de-block-menu-area {
|
|
912
435
|
display: none;
|
|
913
436
|
position: absolute;
|
|
914
|
-
top:
|
|
437
|
+
top: 35px;
|
|
915
438
|
left: 0;
|
|
916
439
|
width: 120px;
|
|
917
440
|
background: #fff;
|
|
918
|
-
|
|
441
|
+
border-width: 0 1px 1px 0;
|
|
442
|
+
border-style: solid;
|
|
443
|
+
border-color: #ccc;
|
|
444
|
+
border-bottom-right-radius: var(--radius-default);
|
|
919
445
|
z-index: 1000;
|
|
920
446
|
}
|
|
921
447
|
.dragon-editor .de-menu-bar .de-block-menu-area.--active {
|
|
@@ -933,12 +459,15 @@ defineExpose({
|
|
|
933
459
|
.dragon-editor .de-menu-bar .de-link-exit-area {
|
|
934
460
|
display: none;
|
|
935
461
|
position: absolute;
|
|
936
|
-
top:
|
|
937
|
-
left:
|
|
462
|
+
top: calc(100% + 1px);
|
|
463
|
+
left: 50%;
|
|
938
464
|
width: 200px;
|
|
939
465
|
background: #fff;
|
|
940
|
-
|
|
466
|
+
border: 1px solid #ccc;
|
|
467
|
+
border-top: 0;
|
|
468
|
+
border-radius: 0 0 var(--radius-default) var(--radius-default);
|
|
941
469
|
z-index: 1000;
|
|
470
|
+
transform: translateX(-50%);
|
|
942
471
|
}
|
|
943
472
|
.dragon-editor .de-menu-bar .de-link-exit-area.--active {
|
|
944
473
|
display: block;
|
|
@@ -950,9 +479,10 @@ defineExpose({
|
|
|
950
479
|
.dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area .de-btn {
|
|
951
480
|
flex: 1;
|
|
952
481
|
height: 24px;
|
|
482
|
+
color: #999;
|
|
953
483
|
}
|
|
954
484
|
.dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area .de-btn.--active {
|
|
955
|
-
|
|
485
|
+
color: #333;
|
|
956
486
|
}
|
|
957
487
|
.dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area {
|
|
958
488
|
display: flex;
|
|
@@ -983,42 +513,40 @@ defineExpose({
|
|
|
983
513
|
overflow-y: auto;
|
|
984
514
|
}
|
|
985
515
|
.dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area .de-btn {
|
|
986
|
-
|
|
516
|
+
padding: 2px 4px;
|
|
987
517
|
text-align: left;
|
|
518
|
+
border-radius: var(--radius-default);
|
|
988
519
|
}
|
|
989
520
|
.dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area .de-btn:hover {
|
|
990
521
|
background: #f1f1f1;
|
|
991
522
|
}
|
|
992
|
-
.dragon-editor .de-
|
|
993
|
-
display:
|
|
523
|
+
.dragon-editor .de-controlbar {
|
|
524
|
+
display: flex;
|
|
994
525
|
position: fixed;
|
|
995
|
-
height:
|
|
526
|
+
height: 34px;
|
|
996
527
|
background: #fff;
|
|
997
528
|
border: 1px solid #ccc;
|
|
998
|
-
border-
|
|
529
|
+
border-radius: var(--radius-default);
|
|
999
530
|
transform: translateX(-50%);
|
|
1000
531
|
z-index: 20;
|
|
1001
532
|
}
|
|
1002
|
-
.dragon-editor .de-
|
|
1003
|
-
display: flex;
|
|
1004
|
-
}
|
|
1005
|
-
.dragon-editor .de-control-bar:empty {
|
|
1006
|
-
display: none;
|
|
1007
|
-
}
|
|
1008
|
-
.dragon-editor .de-control-bar .de-col {
|
|
533
|
+
.dragon-editor .de-controlbar .de-col {
|
|
1009
534
|
display: flex;
|
|
1010
535
|
align-items: center;
|
|
1011
536
|
column-gap: 6px;
|
|
1012
537
|
padding: 0 10px;
|
|
1013
|
-
border: 1px solid #ccc;
|
|
1014
|
-
border-width: 0 1px 1px 0;
|
|
538
|
+
border-right: 1px solid #ccc;
|
|
1015
539
|
}
|
|
1016
|
-
.dragon-editor .de-
|
|
540
|
+
.dragon-editor .de-controlbar .de-col:last-child {
|
|
541
|
+
border-right: 0;
|
|
542
|
+
}
|
|
543
|
+
.dragon-editor .de-controlbar .de-col .de-selector {
|
|
1017
544
|
height: 100%;
|
|
1018
545
|
border: 0;
|
|
1019
546
|
}
|
|
1020
547
|
.dragon-editor .de-block {
|
|
1021
548
|
width: 100%;
|
|
549
|
+
box-sizing: border-box;
|
|
1022
550
|
}
|
|
1023
551
|
.dragon-editor .de-text-block {
|
|
1024
552
|
min-height: 1.6em;
|
|
@@ -1340,14 +868,16 @@ defineExpose({
|
|
|
1340
868
|
.dragon-editor .de-image-block .de-image-area .de-img {
|
|
1341
869
|
width: 100%;
|
|
1342
870
|
height: auto;
|
|
871
|
+
border-radius: var(--radius-default);
|
|
1343
872
|
}
|
|
1344
873
|
.dragon-editor .de-image-block .de-image-area .de-btn {
|
|
1345
874
|
position: absolute;
|
|
1346
875
|
top: 50%;
|
|
1347
876
|
width: 8px;
|
|
1348
|
-
height:
|
|
1349
|
-
background: #
|
|
1350
|
-
border: 1px solid #
|
|
877
|
+
height: 15%;
|
|
878
|
+
background: #f1f1f1;
|
|
879
|
+
border: 1px solid #ccc;
|
|
880
|
+
border-radius: var(--radius-default);
|
|
1351
881
|
transform: translate(-50%, -50%);
|
|
1352
882
|
cursor: col-resize;
|
|
1353
883
|
user-select: none;
|
|
@@ -1375,6 +905,8 @@ defineExpose({
|
|
|
1375
905
|
.dragon-editor .de-code-block {
|
|
1376
906
|
display: flex;
|
|
1377
907
|
flex-wrap: wrap;
|
|
908
|
+
border-radius: var(--radius-default);
|
|
909
|
+
overflow: hidden;
|
|
1378
910
|
}
|
|
1379
911
|
.dragon-editor .de-code-block .de-filename {
|
|
1380
912
|
flex: 1;
|