dragon-editor 3.2.3 → 3.4.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/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "dragon-editor",
3
3
  "configKey": "dragon-editor",
4
- "version": "3.2.3"
4
+ "version": "3.4.0"
5
5
  }
@@ -1,74 +1,112 @@
1
1
  <template>
2
2
  <div class="dragon-editor" :class="{ '--hasMenu': props.useMenuBar === true }" @mousemove="resizeEvent" @touchmove="resizeEvent" @mouseup="resizeEventEnd" @touchend="resizeEventEnd" @mouseleave="resizeEventEnd" ref="$editor">
3
3
  <div v-if="props.useMenuBar === true" class="de-menu-bar" :style="{ top: `${menuBarTop}px` }">
4
- <button class="de-menu de-menu-add" @click="isActiveAddBlockMenu = !isActiveAddBlockMenu">
5
- <svg class="de-icon" viewBox="0 0 64 64">
6
- <path class="de-path" d="M32 9C30.3431 9 29 10.3431 29 12V29H12C10.3431 29 9 30.3431 9 32C9 33.6569 10.3431 35 12 35H29V52C29 53.6569 30.3431 55 32 55C33.6569 55 35 53.6569 35 52V35H52C53.6569 35 55 33.6569 55 32C55 30.3431 53.6569 29 52 29H35V12C35 10.3431 33.6569 9 32 9Z"></path>
7
- </svg>
8
- </button>
9
-
10
- <button class="de-menu" @click="setDecoration('bold')">
11
- <svg class="de-icon" viewBox="0 0 64 64">
12
- <path class="de-path" d="M15 50C15 52.7614 17.2386 55 20 55H32.9922C44.0389 55 49 49.3673 49 41.8571C49 35.1933 45.4069 31.9731 39.714 30.9461C39.6526 30.935 39.607 30.8816 39.607 30.8192C39.607 30.7636 39.6438 30.714 39.6966 30.6965C44.9893 28.9442 47.1479 25.5349 47.1479 20.6006C47.1479 13.1574 42.3191 9 32 9H20C17.2386 9 15 11.2386 15 14V50ZM29.3268 48.2274C26.5654 48.2274 24.3268 45.9888 24.3268 43.2274V39.3469C24.3268 36.5855 26.5654 34.3469 29.3268 34.3469H31.0078C36.3658 34.3469 39.3424 36.3586 39.3424 41.1195C39.3424 45.9475 36.4981 48.2274 31.3385 48.2274H29.3268ZM29.3268 28.4461C26.5654 28.4461 24.3268 26.2075 24.3268 23.4461V20.7055C24.3268 17.9441 26.5654 15.7055 29.3268 15.7055H30.4125C35.3074 15.7055 37.821 17.3149 37.821 22.0087C37.821 26.8367 34.5798 28.4461 30.1479 28.4461H29.3268Z"></path>
13
- </svg>
14
- </button>
15
-
16
- <button class="de-menu" @click="setDecoration('italic')">
17
- <svg class="de-icon" viewBox="0 0 64 64">
18
- <path class="de-path" d="M25 11C25 9.89543 25.8954 9 27 9H34H40H46C47.1046 9 48 9.89543 48 11C48 12.1046 47.1046 13 46 13H39.0435L29.9565 51H36C37.1046 51 38 51.8954 38 53C38 54.1046 37.1046 55 36 55H29H23H17C15.8954 55 15 54.1046 15 53C15 51.8954 15.8954 51 17 51H23.9565L33.0435 13H27C25.8954 13 25 12.1046 25 11Z"></path>
19
- </svg>
20
- </button>
21
-
22
- <button class="de-menu" @click="setDecoration('underline')">
23
- <svg class="de-icon" viewBox="0 0 64 64">
24
- <path class="de-path" d="M21 13C21 11.8954 20.1046 11 19 11C17.8954 11 17 11.8954 17 13V28C17 36.2843 23.7157 43 32 43C40.2843 43 47 36.2843 47 28V13C47 11.8954 46.1046 11 45 11C43.8954 11 43 11.8954 43 13V28C43 34.0751 38.0751 39 32 39C25.9249 39 21 34.0751 21 28V13ZM13 49C11.8954 49 11 49.8954 11 51C11 52.1046 11.8954 53 13 53H51C52.1046 53 53 52.1046 53 51C53 49.8954 52.1046 49 51 49H13Z"></path>
25
- </svg>
26
- </button>
27
-
28
- <button class="de-menu" @click="setDecoration('strikethrough')">
29
- <svg class="de-icon" viewBox="0 0 64 64">
30
- <path
31
- class="de-path"
32
- d="M49 42.0827C49 46.213 47.3861 49.3985 44.1583 51.6391C40.9305 53.8797 36.4003 55 30.5676 55C25.2609 55 20.9589 54.3116 17.6613 52.9349C16.6952 52.5315 16.1274 51.5533 16.1274 50.5064C16.1274 48.407 18.3376 47.0078 20.3303 47.6687C21.2971 47.9893 22.2887 48.2735 23.305 48.5211C25.8816 49.142 28.3591 49.4525 30.7375 49.4525C34.4183 49.4525 37.2497 48.8991 39.2317 47.7923C41.2136 46.6585 42.2046 44.9442 42.2046 42.6496C42.2046 40.9219 41.4118 39.4507 39.8263 38.2359C38.9729 37.5555 37.669 36.8102 35.9145 36H47.1393C48.3798 37.7105 49 39.7381 49 42.0827ZM32.2534 28H19.0141C18.3351 27.3458 17.7693 26.6544 17.3166 25.9261C16.4389 24.4683 16 22.7271 16 20.7025C16 17.0851 17.5431 14.2371 20.6293 12.1585C23.7156 10.0528 27.9485 9 33.3282 9C37.3092 9 41.2187 9.61323 45.0567 10.8397C46.6953 11.3633 47.4248 13.2208 46.708 14.7845C46.04 16.2418 44.353 16.9113 42.8299 16.4114C39.2086 15.2228 35.8715 14.6285 32.8185 14.6285C29.4775 14.6285 26.9575 15.1279 25.2587 16.1268C23.5598 17.1256 22.7104 18.5023 22.7104 20.257C22.7104 21.4448 23.0219 22.4572 23.6448 23.294C24.296 24.1309 25.3295 24.9272 26.7452 25.6831C27.8244 26.2593 29.6605 27.0316 32.2534 28ZM11 30C9.89543 30 9 30.8954 9 32C9 33.1046 9.89543 34 11 34H53C54.1046 34 55 33.1046 55 32C55 30.8954 54.1046 30 53 30H11Z"
33
- ></path>
34
- </svg>
35
- </button>
36
-
37
- <button class="de-menu" @click="setDecoration('code')">
38
- <svg class="de-icon" viewBox="0 0 64 64">
39
- <path class="de-path" d="M35.2981 20C34.5175 20 33.8188 20.4842 33.5447 21.2151L25.9492 41.4698C25.4901 42.6941 26.3951 44 27.7026 44C28.4832 44 29.182 43.5158 29.4561 42.7849L37.0516 22.5302C37.5107 21.3059 36.6056 20 35.2981 20ZM11.013 35.0376C8.34071 33.499 8.34073 29.643 11.013 28.1045L18.8813 23.5745C19.8385 23.0234 21.0613 23.3526 21.6124 24.3098C22.1635 25.2671 21.8343 26.4899 20.8771 27.041L13.0088 31.571L20.8771 36.1011C21.8343 36.6522 22.1635 37.875 21.6124 38.8322C21.0613 39.7895 19.8385 40.1187 18.8813 39.5676L11.013 35.0376ZM53.1299 35.0376C55.8022 33.499 55.8022 29.643 53.1299 28.1045L45.2616 23.5745C44.3044 23.0234 43.0816 23.3526 42.5305 24.3098C41.9794 25.2671 42.3086 26.4899 43.2658 27.041L51.1341 31.571L43.2658 36.1011C42.3086 36.6522 41.9794 37.875 42.5305 38.8322C43.0816 39.7895 44.3044 40.1187 45.2616 39.5676L53.1299 35.0376Z"></path>
40
- </svg>
41
- </button>
42
-
43
- <button class="de-menu" @click="setTextAlign('left')">
44
- <svg class="de-icon" viewBox="0 0 64 64">
45
- <path class="de-path" d="M11 9C9.89543 9 9 9.89543 9 11C9 12.1046 9.89543 13 11 13H23C24.1046 13 25 12.1046 25 11C25 9.89543 24.1046 9 23 9H11Z M11 51C9.89543 51 9 51.8954 9 53C9 54.1046 9.89543 55 11 55H53C54.1046 55 55 54.1046 55 53C55 51.8954 54.1046 51 53 51H11Z M9 39C9 37.8954 9.89543 37 11 37H37C38.1046 37 39 37.8954 39 39C39 40.1046 38.1046 41 37 41H11C9.89543 41 9 40.1046 9 39Z M11 23C9.89543 23 9 23.8954 9 25C9 26.1046 9.89543 27 11 27H53C54.1046 27 55 26.1046 55 25C55 23.8954 54.1046 23 53 23H11Z"></path>
46
- </svg>
47
- </button>
48
-
49
- <button class="de-menu" @click="setTextAlign('center')">
50
- <svg class="de-icon" viewBox="0 0 64 64">
51
- <path class="de-path" d="M24 11C24 9.89543 24.8954 9 26 9H38C39.1046 9 40 9.89543 40 11C40 12.1046 39.1046 13 38 13H26C24.8954 13 24 12.1046 24 11Z M9 53C9 51.8954 9.89543 51 11 51H53C54.1046 51 55 51.8954 55 53C55 54.1046 54.1046 55 53 55H11C9.89543 55 9 54.1046 9 53Z M17 39C17 37.8954 17.8954 37 19 37H45C46.1046 37 47 37.8954 47 39C47 40.1046 46.1046 41 45 41H19C17.8954 41 17 40.1046 17 39Z M9 25C9 23.8954 9.89543 23 11 23H53C54.1046 23 55 23.8954 55 25C55 26.1046 54.1046 27 53 27H11C9.89543 27 9 26.1046 9 25Z"></path>
52
- </svg>
53
- </button>
54
-
55
- <button class="de-menu" @click="setTextAlign('right')">
56
- <svg class="de-icon" viewBox="0 0 64 64">
57
- <path class="de-path" d="M39 11C39 9.89543 39.8954 9 41 9H53C54.1046 9 55 9.89543 55 11C55 12.1046 54.1046 13 53 13H41C39.8954 13 39 12.1046 39 11Z M9 53C9 51.8954 9.89543 51 11 51H53C54.1046 51 55 51.8954 55 53C55 54.1046 54.1046 55 53 55H11C9.89543 55 9 54.1046 9 53Z M25 39C25 37.8954 25.8954 37 27 37H53C54.1046 37 55 37.8954 55 39C55 40.1046 54.1046 41 53 41H27C25.8954 41 25 40.1046 25 39Z M9 25C9 23.8954 9.89543 23 11 23H53C54.1046 23 55 23.8954 55 25C55 26.1046 54.1046 27 53 27H11C9.89543 27 9 26.1046 9 25Z"></path>
58
- </svg>
59
- </button>
60
-
61
- <button class="de-menu" @click="setTextAlign('justify')">
62
- <svg class="de-icon" viewBox="0 0 64 64">
63
- <path class="de-path" d="M9 53C9 51.8954 9.89543 51 11 51H53C54.1046 51 55 51.8954 55 53C55 54.1046 54.1046 55 53 55H11C9.89543 55 9 54.1046 9 53Z M9 39C9 37.8954 9.89543 37 11 37H53C54.1046 37 55 37.8954 55 39C55 40.1046 54.1046 41 53 41H11C9.89543 41 9 40.1046 9 39Z M9 11C9 9.89543 9.89543 9 11 9H53C54.1046 9 55 9.89543 55 11C55 12.1046 54.1046 13 53 13H11C9.89543 13 9 12.1046 9 11Z M9 25C9 23.8954 9.89543 23 11 23H53C54.1046 23 55 23.8954 55 25C55 26.1046 54.1046 27 53 27H11C9.89543 27 9 26.1046 9 25Z"></path>
64
- </svg>
65
- </button>
66
-
67
- <button class="de-menu" @click="deleteBlock">
68
- <svg class="de-icon" viewBox="0 0 64 64">
69
- <path class="de-path --red" fill-rule="evenodd" clip-rule="evenodd" d="M32 51C42.4934 51 51 42.4934 51 32C51 21.5066 42.4934 13 32 13C21.5066 13 13 21.5066 13 32C13 42.4934 21.5066 51 32 51ZM32 55C44.7026 55 55 44.7026 55 32C55 19.2974 44.7026 9 32 9C19.2974 9 9 19.2974 9 32C9 44.7026 19.2974 55 32 55ZM21.4142 42.6274C20.6332 41.8462 20.6332 40.5801 21.4142 39.7988L29.1715 32.0415L21.5858 24.4558C20.8047 23.6748 20.8047 22.4084 21.5858 21.6274C22.3668 20.8462 23.6332 20.8462 24.4142 21.6274L31.9999 29.2131L39.799 21.4141C40.58 20.6331 41.8464 20.6331 42.6274 21.4141C43.4084 22.1953 43.4084 23.4614 42.6274 24.2427L34.8284 32.0417L42.799 40.0122C43.58 40.7932 43.58 42.0596 42.799 42.8406C42.0179 43.6216 40.7516 43.6216 39.9706 42.8406L32.0001 34.8701L24.2426 42.6274C23.4616 43.4084 22.1953 43.4084 21.4142 42.6274Z"></path>
70
- </svg>
71
- </button>
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>
72
110
 
73
111
  <div class="de-block-menu-area" :class="{ '--active': isActiveAddBlockMenu }">
74
112
  <div class="de-list">
@@ -83,6 +121,22 @@
83
121
  <!-- <button class="de-add-block" @click="addBlock('video')">Video</button> youtube | vimeo -->
84
122
  </div>
85
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>
86
140
  </div>
87
141
 
88
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">
@@ -132,7 +186,7 @@ import { _getCodeBlockTheme, _getCodeBlockLanguage, _setCodeBlockTheme, _setCode
132
186
  import { _findScrollingElement, _findContentEditableElement } from "../utils/element";
133
187
  import { _elementKeyEvent, _hotKeyEvent, _copyEvent, _pasteEvent } from "../utils/keyboardEvent";
134
188
  import { _getBlockType, _createTextBlock, _createHeadingBlock, _createListBlock, _createImageBlock, _createCustomBlock, _createCodeBlock } from "../utils/block";
135
- import { _setNodeStyle, _setTextAlign } from "../utils/style";
189
+ import { _setNodeStyle, _setTextAlign, _setAnchorTag, _unsetAnchorTag, _getAnchorTagValue } from "../utils/style";
136
190
  import { _setCursor, _setCursorData, _clenupCursor } from "../utils/cursor";
137
191
  import { _getContentData, _setContentData } from "../utils/convertor";
138
192
  import { _addBlockToContent } from "../utils/content";
@@ -144,9 +198,14 @@ const props = defineProps({
144
198
  requiard: false,
145
199
  default: () => true,
146
200
  },
201
+ imageHostURL: {
202
+ type: String,
203
+ requiard: false,
204
+ default: () => "",
205
+ },
147
206
  });
148
207
  const emit = defineEmits<{
149
- (e: "addPasteImage", file: File): DEImage;
208
+ (e: "uploadImageEvent", file: File): DEImage;
150
209
  }>();
151
210
  const editorStore = useEditorStore();
152
211
  const isActiveAddBlockMenu = ref<boolean>(false);
@@ -155,10 +214,15 @@ const curruntType = ref<string>("");
155
214
  const codeBlockTheme = ref<string>("github");
156
215
  const codeblockLanguage = ref<string>("text");
157
216
  const listBlockStyle = ref<DEListStyle>("disc");
217
+ const isActiveLinkArea = ref<boolean>(false);
218
+ const anchorValueError = ref<boolean>(false);
219
+ const activeLinkTabType = ref<"url" | "heading">("url");
220
+ const anchorHeadingList = ref<DEHeadingItem[]>([]);
158
221
  const anchorTagValue = ref<string>("");
159
222
  const $editor = ref<HTMLDivElement>();
160
223
  const $content = ref<HTMLDivElement>();
161
224
  const $controlBar = ref<HTMLDivElement>();
225
+ const $linkInput = ref<HTMLInputElement>();
162
226
  let resizeEventActive: boolean = false;
163
227
  let resizeStartX: number = 0;
164
228
  let resizeType: string = "right";
@@ -177,7 +241,7 @@ function contentKeyboardEvent(e: KeyboardEvent) {
177
241
  function updateCursorData(e: MouseEvent) {
178
242
  const originalCursorData = editorStore.cursorData;
179
243
 
180
- _setCursorData(editorStore);
244
+ _clenupCursor(editorStore);
181
245
 
182
246
  if (editorStore.cursorData !== null && _findContentEditableElement(editorStore.cursorData.startNode) === null) {
183
247
  // 비정상 커서 값일 경우 초기화
@@ -194,7 +258,9 @@ function updateCursorData(e: MouseEvent) {
194
258
  }
195
259
 
196
260
  controlBarStatusUpdate();
261
+ anchorTagValueUpdate();
197
262
  }
263
+
198
264
  // 컨트롤 바 상태 업데이트
199
265
  function controlBarStatusUpdate() {
200
266
  if (editorStore.$currentBlock !== null) {
@@ -296,10 +362,34 @@ function resizeEventEnd() {
296
362
  function checkOthersideClick(event: MouseEvent) {
297
363
  if (event.target !== null) {
298
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;
299
371
 
300
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) {
301
386
  isActiveAddBlockMenu.value = false;
302
387
  }
388
+
389
+ if (closeLink === true) {
390
+ isActiveLinkArea.value = false;
391
+ anchorTagValue.value = "";
392
+ }
303
393
  }
304
394
  }
305
395
 
@@ -323,8 +413,6 @@ function deleteBlock() {
323
413
 
324
414
  // 부모 요소 스크롤 이벤트 발생시 컨트롤 바 고정
325
415
  function parentWrapScollEvent() {
326
- editorStore.setParentWrapElement(_findScrollingElement($editor.value as HTMLElement));
327
-
328
416
  if (props.useMenuBar === true && editorStore.$parentWrap !== null && editorStore.$editor !== null) {
329
417
  // 메뉴바를 사용하는 경우만
330
418
 
@@ -345,11 +433,19 @@ function parentWrapScollEvent() {
345
433
  realElementY -= parentRect.y;
346
434
  }
347
435
 
436
+ let value: number = 0;
437
+
348
438
  if (scrollY > realElementY) {
349
- menuBarTop.value = scrollY - realElementY - 1;
439
+ value = scrollY - realElementY - 1;
350
440
  } else {
351
- menuBarTop.value = 0;
441
+ value = 0;
352
442
  }
443
+
444
+ if (value > editorReac.height - 39) {
445
+ value = editorReac.height - 39;
446
+ }
447
+
448
+ menuBarTop.value = Math.floor(value);
353
449
  }
354
450
  }
355
451
 
@@ -358,6 +454,13 @@ function contentPasteEvent(event: ClipboardEvent) {
358
454
  _pasteEvent(event, editorStore, emit);
359
455
  }
360
456
 
457
+ function anchorTagValueUpdate() {
458
+ // 다른 이벤트 순서에 의한 딜레이
459
+ setTimeout(() => {
460
+ anchorTagValue.value = _getAnchorTagValue(editorStore);
461
+ }, 500);
462
+ }
463
+
361
464
  /**
362
465
  * 이벤트 관련 영역 종료
363
466
  */
@@ -385,6 +488,9 @@ function listBlockStyleChangeEvent() {
385
488
  * 컨트롤 바 이벤트 관련 영역 종료
386
489
  */
387
490
 
491
+ /**
492
+ * 메뉴 이벤트 관련 영역
493
+ */
388
494
  function addBlock(type: string) {
389
495
  isActiveAddBlockMenu.value = false;
390
496
 
@@ -466,6 +572,10 @@ function addCustomBlock(HTML: string, classList: string[] = []) {
466
572
  }
467
573
 
468
574
  function addImageBlock(data: DEImage) {
575
+ if (props.imageHostURL !== "") {
576
+ data.src = props.imageHostURL + data.src;
577
+ }
578
+
469
579
  const blockStructure = _createImageBlock({
470
580
  ...data,
471
581
  type: "image",
@@ -486,7 +596,7 @@ function setTextAlign(type: DETextalign) {
486
596
 
487
597
  function getContentData(): DEContentData {
488
598
  if (editorStore.$content !== null) {
489
- return _getContentData(editorStore.$content);
599
+ return _getContentData(editorStore.$content, props.imageHostURL);
490
600
  } else {
491
601
  console.error("[DragonEditor] Con't find content Element.");
492
602
  return [];
@@ -497,6 +607,90 @@ function setContentData(data: DEContentData) {
497
607
  _setContentData(data, editorStore);
498
608
  }
499
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);
626
+ } else {
627
+ editorStore.setCurrentBlock(($target as HTMLElement).nextElementSibling as HTMLElement | null);
628
+ }
629
+ }
630
+ }
631
+ }
632
+
633
+ function openLinkArea() {
634
+ activeLinkTabType.value = "url";
635
+ anchorValueError.value = false;
636
+ }
637
+
638
+ function chooseMediaEvent(event: Event) {
639
+ const $target = event.target as HTMLInputElement;
640
+ const file = $target.files![0];
641
+
642
+ emit("uploadImageEvent", file);
643
+ $target.value = "";
644
+ }
645
+
646
+ // 링크 삽입
647
+ function setLink() {
648
+ if ($linkInput.value !== null && $linkInput.value?.checkValidity() === true && anchorTagValue.value !== "") {
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 = "";
663
+ }
664
+
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
+
500
694
  onMounted(() => {
501
695
  if ($editor.value !== undefined) {
502
696
  editorStore.setWrapElement($editor.value);
@@ -674,7 +868,8 @@ defineExpose({
674
868
  padding-top: 38px;
675
869
  }
676
870
  .dragon-editor .de-body {
677
- display: grid;
871
+ display: flex;
872
+ flex-direction: column;
678
873
  gap: 4px;
679
874
  padding: 20px;
680
875
  line-height: 1.6;
@@ -689,12 +884,23 @@ defineExpose({
689
884
  border-bottom: 1px solid #ccc;
690
885
  z-index: 10;
691
886
  }
887
+ .dragon-editor .de-menu-bar .de-menu-wrap {
888
+ display: flex;
889
+ overflow-x: auto;
890
+ }
692
891
  .dragon-editor .de-menu-bar .de-menu {
892
+ display: flex;
893
+ justify-content: center;
894
+ align-items: center;
693
895
  min-width: 38px;
694
896
  height: 38px;
695
- padding: 0 8px;
696
897
  border-right: 1px solid #ccc;
697
898
  box-sizing: border-box;
899
+ cursor: pointer;
900
+ }
901
+ .dragon-editor .de-menu-bar .de-menu .de-icon {
902
+ width: 24px;
903
+ height: 24px;
698
904
  }
699
905
  .dragon-editor .de-menu-bar .de-menu.--lastchild {
700
906
  border-right: 0;
@@ -724,6 +930,65 @@ defineExpose({
724
930
  .dragon-editor .de-menu-bar .de-block-menu-area .de-add-block {
725
931
  line-height: 1.6;
726
932
  }
933
+ .dragon-editor .de-menu-bar .de-link-exit-area {
934
+ display: none;
935
+ position: absolute;
936
+ top: 39px;
937
+ left: 228px;
938
+ width: 200px;
939
+ background: #fff;
940
+ box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
941
+ z-index: 1000;
942
+ }
943
+ .dragon-editor .de-menu-bar .de-link-exit-area.--active {
944
+ display: block;
945
+ }
946
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area {
947
+ display: flex;
948
+ border-bottom: 1px solid #ccc;
949
+ }
950
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area .de-btn {
951
+ flex: 1;
952
+ height: 24px;
953
+ }
954
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area .de-btn.--active {
955
+ background: #f1f1f1;
956
+ }
957
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area {
958
+ display: flex;
959
+ column-gap: 10px;
960
+ padding: 4px;
961
+ }
962
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area .de-input {
963
+ flex: 1;
964
+ min-width: 0;
965
+ height: 20px;
966
+ padding: 0 8px;
967
+ border: 1px solid #ccc;
968
+ box-sizing: border-box;
969
+ }
970
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area .de-input.--red {
971
+ border-color: red;
972
+ }
973
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area .de-btn {
974
+ min-width: 50px;
975
+ height: 20px;
976
+ }
977
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area {
978
+ display: flex;
979
+ flex-direction: column;
980
+ max-height: 150px;
981
+ padding: 8px;
982
+ box-sizing: border-box;
983
+ overflow-y: auto;
984
+ }
985
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area .de-btn {
986
+ min-height: 20px;
987
+ text-align: left;
988
+ }
989
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area .de-btn:hover {
990
+ background: #f1f1f1;
991
+ }
727
992
  .dragon-editor .de-control-bar {
728
993
  display: none;
729
994
  position: fixed;
@@ -1399,4 +1664,8 @@ defineExpose({
1399
1664
  .dragon-editor .de-align-justify {
1400
1665
  text-align: justify;
1401
1666
  }
1667
+ .dragon-editor .de-link {
1668
+ color: #2c95fe;
1669
+ text-decoration: none;
1670
+ }
1402
1671
  </style>
@@ -21,7 +21,7 @@
21
21
 
22
22
  <div v-if="item.type === 'image'" class="de-block de-image-block" :class="item.classList">
23
23
  <div class="de-image-area" :data-maxwidth="item.maxWidth">
24
- <img :src="item.src" alt="" class="de-img" :width="item.width" :height="item.height" loading="lazy" />
24
+ <img :src="props.imageHostURL === undefined ? item.src : props.imageHostURL + item.src" alt="" class="de-img" :width="item.width" :height="item.height" loading="lazy" />
25
25
  </div>
26
26
 
27
27
  <p v-if="item.caption" class="de-caption">{{ item.caption }}</p>
@@ -41,6 +41,7 @@
41
41
  <script setup lang="ts">
42
42
  const props = defineProps<{
43
43
  content: DEContentData;
44
+ imageHostURL?: string;
44
45
  }>();
45
46
  </script>
46
47
 
@@ -782,4 +783,8 @@ const props = defineProps<{
782
783
  .dragon-editor-viewer .de-align-justify {
783
784
  text-align: justify;
784
785
  }
786
+ .dragon-editor-viewer .de-link {
787
+ color: #2c95fe;
788
+ text-decoration: none;
789
+ }
785
790
  </style>
@@ -140,7 +140,8 @@
140
140
  padding-top: 38px;
141
141
  }
142
142
  .dragon-editor .de-body {
143
- display: grid;
143
+ display: flex;
144
+ flex-direction: column;
144
145
  gap: 4px;
145
146
  padding: 20px;
146
147
  line-height: 1.6;
@@ -155,12 +156,23 @@
155
156
  border-bottom: 1px solid #ccc;
156
157
  z-index: 10;
157
158
  }
159
+ .dragon-editor .de-menu-bar .de-menu-wrap {
160
+ display: flex;
161
+ overflow-x: auto;
162
+ }
158
163
  .dragon-editor .de-menu-bar .de-menu {
164
+ display: flex;
165
+ justify-content: center;
166
+ align-items: center;
159
167
  min-width: 38px;
160
168
  height: 38px;
161
- padding: 0 8px;
162
169
  border-right: 1px solid #ccc;
163
170
  box-sizing: border-box;
171
+ cursor: pointer;
172
+ }
173
+ .dragon-editor .de-menu-bar .de-menu .de-icon {
174
+ width: 24px;
175
+ height: 24px;
164
176
  }
165
177
  .dragon-editor .de-menu-bar .de-menu.--lastchild {
166
178
  border-right: 0;
@@ -190,6 +202,65 @@
190
202
  .dragon-editor .de-menu-bar .de-block-menu-area .de-add-block {
191
203
  line-height: 1.6;
192
204
  }
205
+ .dragon-editor .de-menu-bar .de-link-exit-area {
206
+ display: none;
207
+ position: absolute;
208
+ top: 39px;
209
+ left: 228px;
210
+ width: 200px;
211
+ background: #fff;
212
+ box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
213
+ z-index: 1000;
214
+ }
215
+ .dragon-editor .de-menu-bar .de-link-exit-area.--active {
216
+ display: block;
217
+ }
218
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area {
219
+ display: flex;
220
+ border-bottom: 1px solid #ccc;
221
+ }
222
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area .de-btn {
223
+ flex: 1;
224
+ height: 24px;
225
+ }
226
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-btn-area .de-btn.--active {
227
+ background: #f1f1f1;
228
+ }
229
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area {
230
+ display: flex;
231
+ column-gap: 10px;
232
+ padding: 4px;
233
+ }
234
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area .de-input {
235
+ flex: 1;
236
+ min-width: 0;
237
+ height: 20px;
238
+ padding: 0 8px;
239
+ border: 1px solid #ccc;
240
+ box-sizing: border-box;
241
+ }
242
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area .de-input.--red {
243
+ border-color: red;
244
+ }
245
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-text-area .de-btn {
246
+ min-width: 50px;
247
+ height: 20px;
248
+ }
249
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area {
250
+ display: flex;
251
+ flex-direction: column;
252
+ max-height: 150px;
253
+ padding: 8px;
254
+ box-sizing: border-box;
255
+ overflow-y: auto;
256
+ }
257
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area .de-btn {
258
+ min-height: 20px;
259
+ text-align: left;
260
+ }
261
+ .dragon-editor .de-menu-bar .de-link-exit-area .de-link-heading-area .de-btn:hover {
262
+ background: #f1f1f1;
263
+ }
193
264
  .dragon-editor .de-control-bar {
194
265
  display: none;
195
266
  position: fixed;
@@ -864,4 +935,8 @@
864
935
  }
865
936
  .dragon-editor .de-align-justify {
866
937
  text-align: justify;
938
+ }
939
+ .dragon-editor .de-link {
940
+ color: #2c95fe;
941
+ text-decoration: none;
867
942
  }
@@ -734,4 +734,8 @@
734
734
  }
735
735
  .dragon-editor-viewer .de-align-justify {
736
736
  text-align: justify;
737
+ }
738
+ .dragon-editor-viewer .de-link {
739
+ color: #2c95fe;
740
+ text-decoration: none;
737
741
  }
@@ -43,6 +43,11 @@ interface DECodeItem {
43
43
  code: string;
44
44
  }
45
45
 
46
+ interface DEHeadingItem {
47
+ name: string;
48
+ id: string;
49
+ }
50
+
46
51
  type DEDecoration = "bold" | "italic" | "underline" | "strikethrough" | "code";
47
52
 
48
53
  type DETextalign = "left" | "right" | "center" | "justify";
@@ -1,3 +1,3 @@
1
1
  import "../type.d.ts";
2
- export declare function _getContentData($content: HTMLDivElement): DEContentData;
2
+ export declare function _getContentData($content: HTMLDivElement, imageHostURL: string): DEContentData;
3
3
  export declare function _setContentData(data: DEContentData, store: any): void;
@@ -1,6 +1,6 @@
1
1
  import { _createTextBlock, _createHeadingBlock, _createListBlock, _createImageBlock, _createCodeBlock, _createCustomBlock } from "./block.mjs";
2
2
  import "../type.d.ts";
3
- export function _getContentData($content) {
3
+ export function _getContentData($content, imageHostURL) {
4
4
  const childList = $content.children;
5
5
  const data = [];
6
6
  [...childList].forEach(($child) => {
@@ -23,7 +23,7 @@ export function _getContentData($content) {
23
23
  data.push(converteListToData($child));
24
24
  break;
25
25
  case "DIV":
26
- data.push(converteDivToData($child));
26
+ data.push(converteDivToData($child, imageHostURL));
27
27
  break;
28
28
  }
29
29
  });
@@ -84,11 +84,11 @@ function converteListToData($child) {
84
84
  })
85
85
  };
86
86
  }
87
- function converteDivToData($child) {
87
+ function converteDivToData($child, imageHostURL) {
88
88
  let data;
89
89
  switch (true) {
90
90
  case $child.classList.contains("de-image-block"):
91
- data = convertImageBlock($child);
91
+ data = convertImageBlock($child, imageHostURL);
92
92
  break;
93
93
  case $child.classList.contains("de-code-block"):
94
94
  data = convertCodeBlock($child);
@@ -99,13 +99,13 @@ function converteDivToData($child) {
99
99
  }
100
100
  return data;
101
101
  }
102
- function convertImageBlock($imageBlock) {
102
+ function convertImageBlock($imageBlock, imageHostURL) {
103
103
  const $imgArea = $imageBlock.querySelector(".de-image-area");
104
104
  const $img = $imageBlock.querySelector(".de-img");
105
105
  const $caption = $imageBlock.querySelector(".de-caption");
106
106
  return {
107
107
  type: "image",
108
- src: $img.src,
108
+ src: imageHostURL === "" ? $img.src : $img.src.replace(imageHostURL, ""),
109
109
  maxWidth: parseInt($imgArea.dataset["maxwidth"]),
110
110
  width: $img.width,
111
111
  height: $img.height,
@@ -965,7 +965,7 @@ export async function _pasteEvent(event, store, emit) {
965
965
  if (imageItem !== void 0) {
966
966
  const blob = await clipboardItems[0].getType(imageItem);
967
967
  const file = new File([blob], `${_generateId()}.${imageItem.split("/")[1]}`);
968
- emit("addPasteImage", file);
968
+ emit("uploadImageEvent", file);
969
969
  }
970
970
  } else {
971
971
  const selection = window.getSelection();
@@ -1,2 +1,5 @@
1
1
  export declare function _setNodeStyle(className: string, store: any): void;
2
2
  export declare function _setTextAlign(type: DETextalign, store: any): void;
3
+ export declare function _setAnchorTag(url: string, isOutsideLink: boolean, store: any): void;
4
+ export declare function _unsetAnchorTag(store: any): false | undefined;
5
+ export declare function _getAnchorTagValue(store: any): string;
@@ -14,20 +14,21 @@ export function _setNodeStyle(className, store) {
14
14
  if ($target.constructor.name === "Text") {
15
15
  const $parentElement = $target.parentElement;
16
16
  if ($parentElement === $element) {
17
- const childList = $element.childNodes;
17
+ let childList = $element.childNodes;
18
18
  let targetIdx = -1;
19
19
  let structure = "";
20
- let cursorOffset = 0;
21
20
  for (let i = 0; childList.length > i; i += 1) {
22
21
  if ($target === childList[i]) {
23
22
  targetIdx = i;
24
23
  break;
25
24
  }
26
25
  }
26
+ targetIdx = findPoverTextNode(childList[targetIdx], targetIdx);
27
+ $element.innerHTML = $element.innerHTML;
28
+ childList = $element.childNodes;
27
29
  childList.forEach((node, i) => {
28
30
  if (i === targetIdx) {
29
31
  structure += `<span class="${className}">${node.textContent}</span>`;
30
- cursorOffset = node.textContent.length;
31
32
  } else {
32
33
  if (node.constructor.name === "Text") {
33
34
  structure += node.textContent;
@@ -37,22 +38,26 @@ export function _setNodeStyle(className, store) {
37
38
  }
38
39
  });
39
40
  $element.innerHTML = structure;
40
- _setCursor($element.childNodes[targetIdx], cursorOffset);
41
+ const targetElement = $element.childNodes[targetIdx];
42
+ _setRangeCursor(targetElement, targetElement, 0, targetElement.textContent?.length ?? 0);
41
43
  } else {
42
44
  if ($parentElement.tagName === "SPAN") {
43
45
  const classList = $parentElement.classList.value.split(" ");
44
46
  const classIdx = classList.indexOf(className);
45
47
  if (classIdx === -1) {
46
48
  $parentElement.classList.add(className);
47
- _setCursor($parentElement.childNodes[0], store.cursorData.startOffset);
49
+ const targetNode = $parentElement.childNodes[0];
50
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
48
51
  } else {
49
52
  if (classList.length === 1) {
50
53
  $parentElement.insertAdjacentText("afterend", $parentElement.textContent);
51
- _setCursor($parentElement.nextSibling, store.cursorData.startOffset);
54
+ const targetNode = $parentElement.nextSibling;
52
55
  $parentElement.remove();
56
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
53
57
  } else {
54
58
  $parentElement.classList.remove(className);
55
- _setCursor($parentElement.childNodes[0], store.cursorData.startOffset);
59
+ const targetNode = $parentElement.childNodes[0];
60
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
56
61
  }
57
62
  }
58
63
  }
@@ -88,7 +93,8 @@ export function _setNodeStyle(className, store) {
88
93
  childNumber += 1;
89
94
  }
90
95
  $element.innerHTML = structure;
91
- _setCursor($element.childNodes[childNumber], cursorData.endOffset - cursorData.startOffset);
96
+ const targetNode = $element.childNodes[childNumber];
97
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
92
98
  } else {
93
99
  const $target = cursorData.startNode;
94
100
  if ($target.tagName !== "A") {
@@ -125,7 +131,8 @@ export function _setNodeStyle(className, store) {
125
131
  $nextElement = $nextElement.nextSibling;
126
132
  }
127
133
  $target.remove();
128
- _setCursor($nextElement, cursorData.endOffset - cursorData.startOffset);
134
+ const targetNode = $nextElement;
135
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
129
136
  }
130
137
  }
131
138
  } else {
@@ -363,3 +370,248 @@ export function _setTextAlign(type, store) {
363
370
  }
364
371
  }
365
372
  }
373
+ export function _setAnchorTag(url, isOutsideLink, store) {
374
+ if (store.cursorData !== null) {
375
+ const { type } = _getBlockType(store.$currentBlock);
376
+ const typeIgnoreList = ["image", "code", "other"];
377
+ const hrefValue = isOutsideLink === true ? url : `#${url}`;
378
+ if (typeIgnoreList.includes(type) === false) {
379
+ const $element = _findContentEditableElement(store.cursorData.startNode);
380
+ if ($element !== null) {
381
+ if (store.cursorData.type === "Caret") {
382
+ if ($element.hasChildNodes() === true) {
383
+ let $target = store.cursorData.startNode;
384
+ if ($target.constructor.name === "Text") {
385
+ const $parentElement = $target.parentElement;
386
+ if ($parentElement === $element) {
387
+ let childList = $element.childNodes;
388
+ let targetIdx = -1;
389
+ let structure = "";
390
+ for (let i = 0; childList.length > i; i += 1) {
391
+ if ($target === childList[i]) {
392
+ targetIdx = i;
393
+ break;
394
+ }
395
+ }
396
+ targetIdx = findPoverTextNode(childList[targetIdx], targetIdx);
397
+ $element.innerHTML = $element.innerHTML;
398
+ childList = $element.childNodes;
399
+ childList.forEach((node, i) => {
400
+ if (i === targetIdx) {
401
+ structure += `<a class="de-link"`;
402
+ structure += `href="${hrefValue}"`;
403
+ if (isOutsideLink === true) {
404
+ structure += `target="_blank"`;
405
+ }
406
+ structure += `>`;
407
+ structure += `${node.textContent}</a>`;
408
+ } else {
409
+ if (node.constructor.name === "Text") {
410
+ structure += node.textContent;
411
+ } else {
412
+ structure += node.outerHTML;
413
+ }
414
+ }
415
+ });
416
+ $element.innerHTML = structure;
417
+ const targetElement = $element.childNodes[targetIdx];
418
+ _setRangeCursor(targetElement, targetElement, 0, targetElement.textContent?.length ?? 0);
419
+ } else {
420
+ if ($parentElement.tagName === "A") {
421
+ $parentElement.href = hrefValue;
422
+ if (isOutsideLink === true) {
423
+ $parentElement.target = "_blank";
424
+ } else {
425
+ $parentElement.removeAttribute("target");
426
+ }
427
+ _setRangeCursor($parentElement, $parentElement, 0, $parentElement.textContent?.length ?? 0);
428
+ }
429
+ }
430
+ }
431
+ }
432
+ } else {
433
+ const cursorData = _soltingCursorDataOnElement(store.cursorData, $element);
434
+ let structure = "";
435
+ let isDuble = false;
436
+ if (cursorData.startNodeIdx === cursorData.endNodeIdx) {
437
+ if (cursorData.startNode.constructor.name === "Text") {
438
+ $element.childNodes.forEach((childNode, i) => {
439
+ if (cursorData.startNodeIdx === i) {
440
+ if (cursorData.startOffset !== 0) {
441
+ structure += childNode.textContent.slice(0, cursorData.startOffset);
442
+ isDuble = true;
443
+ }
444
+ structure += `<a class="de-link"`;
445
+ structure += `href="${hrefValue}"`;
446
+ if (isOutsideLink === true) {
447
+ structure += `target="_blank"`;
448
+ }
449
+ structure += `>`;
450
+ structure += `${childNode.textContent.slice(cursorData.startOffset, cursorData.endOffset)}</a>`;
451
+ if (cursorData.endOffset !== childNode.textContent.length) {
452
+ structure += childNode.textContent.slice(cursorData.endOffset);
453
+ }
454
+ } else {
455
+ if (childNode.constructor.name === "Text") {
456
+ structure += childNode.textContent;
457
+ } else {
458
+ structure += childNode.outerHTML;
459
+ }
460
+ }
461
+ });
462
+ let childNumber = cursorData.startNodeIdx;
463
+ if (isDuble === true) {
464
+ childNumber += 1;
465
+ }
466
+ $element.innerHTML = structure;
467
+ const targetNode = $element.childNodes[childNumber];
468
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
469
+ } else {
470
+ const $target = cursorData.startNode;
471
+ if ($target.tagName !== "A") {
472
+ const classList = $target.classList.value.split(" ");
473
+ if (cursorData.startOffset !== 0) {
474
+ structure += `<span class="${classList.join(" ")}">${$target.textContent.slice(0, cursorData.startOffset)}</span>`;
475
+ isDuble = true;
476
+ }
477
+ structure += `<a class="de-link"`;
478
+ structure += `href="${hrefValue}"`;
479
+ if (isOutsideLink === true) {
480
+ structure += `target="_blank"`;
481
+ }
482
+ structure += `>`;
483
+ structure += `${$target.textContent.slice(cursorData.startOffset, cursorData.endOffset)}</a>`;
484
+ if (cursorData.endOffset !== $target.textContent.length) {
485
+ structure += `<span class="${classList.join(" ")}">${$target.textContent.slice(cursorData.endOffset)}</span>`;
486
+ }
487
+ $target.insertAdjacentHTML("afterend", structure);
488
+ let $nextElement = $target.nextSibling;
489
+ if (isDuble === true) {
490
+ $nextElement = $nextElement.nextSibling;
491
+ }
492
+ $target.remove();
493
+ const targetNode = $nextElement;
494
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
495
+ } else {
496
+ $target.href = hrefValue;
497
+ if (isOutsideLink === true) {
498
+ $target.target = "_blank";
499
+ } else {
500
+ $target.removeAttribute("target");
501
+ }
502
+ _setRangeCursor($target, $target, 0, $target.textContent?.length ?? 0);
503
+ }
504
+ }
505
+ } else {
506
+ let preStructure = "";
507
+ let anchorTextContent = "";
508
+ let nextStructure = "";
509
+ $element.childNodes.forEach((childNode, i) => {
510
+ const $elementNode = childNode;
511
+ let isText = childNode.constructor.name === "Text";
512
+ if (cursorData.startNodeIdx > i) {
513
+ if (isText === true) {
514
+ preStructure += childNode.textContent;
515
+ } else {
516
+ preStructure += $elementNode.outerHTML;
517
+ }
518
+ }
519
+ if (cursorData.startNodeIdx === i) {
520
+ if (isText === true) {
521
+ preStructure += childNode.textContent.slice(0, cursorData.startOffset);
522
+ } else {
523
+ preStructure += `<span class="${childNode.classList.value}">${childNode.textContent.slice(0, cursorData.startOffset)}</span>`;
524
+ }
525
+ anchorTextContent += childNode.textContent.slice(cursorData.startOffset);
526
+ }
527
+ if (cursorData.startNodeIdx < i && cursorData.endNodeIdx > i) {
528
+ anchorTextContent += childNode.textContent;
529
+ }
530
+ if (cursorData.endNodeIdx === i) {
531
+ anchorTextContent += childNode.textContent.slice(0, cursorData.endOffset);
532
+ if (isText === true) {
533
+ nextStructure += childNode.textContent.slice(cursorData.startOffset);
534
+ } else {
535
+ nextStructure += `<span class="${childNode.classList.value}">${childNode.textContent.slice(cursorData.startOffset)}</span>`;
536
+ }
537
+ }
538
+ if (cursorData.endNodeIdx < i) {
539
+ if (isText === true) {
540
+ nextStructure += childNode.textContent;
541
+ } else {
542
+ nextStructure += $elementNode.outerHTML;
543
+ }
544
+ }
545
+ });
546
+ let anchorTag = "";
547
+ anchorTag += `<a class="de-link"`;
548
+ anchorTag += `href="${hrefValue}"`;
549
+ if (isOutsideLink === true) {
550
+ anchorTag += `target="_blank"`;
551
+ }
552
+ anchorTag += `>`;
553
+ anchorTag += anchorTextContent;
554
+ anchorTag += `</a>`;
555
+ $element.innerHTML = preStructure + anchorTag + nextStructure;
556
+ let targetNode = $element.childNodes[cursorData.startNodeIdx];
557
+ if (cursorData.startOffset !== 0) {
558
+ targetNode = $element.childNodes[cursorData.startNodeIdx + 1];
559
+ }
560
+ _setRangeCursor(targetNode, targetNode, 0, targetNode.textContent?.length ?? 0);
561
+ }
562
+ }
563
+ }
564
+ _clenupCursor(store);
565
+ }
566
+ }
567
+ }
568
+ export function _unsetAnchorTag(store) {
569
+ if (store.cursorData !== null) {
570
+ const $element = _findContentEditableElement(store.cursorData.startNode);
571
+ if ($element !== null) {
572
+ const cursorData = _soltingCursorDataOnElement(store.cursorData, $element);
573
+ if (cursorData.startNode.constructor.name === "HTMLAnchorElement") {
574
+ if (store.cursorData.type === "Range") {
575
+ if (cursorData.startNodeIdx !== cursorData.endNodeIdx) {
576
+ return false;
577
+ }
578
+ }
579
+ const $anchorTag = cursorData.startNode;
580
+ $anchorTag.insertAdjacentText("afterend", cursorData.startNode.textContent ?? "");
581
+ const $targetNode = $anchorTag.nextSibling;
582
+ $anchorTag.remove();
583
+ _setRangeCursor($targetNode, $targetNode, 0, $targetNode.textContent?.length ?? 0);
584
+ }
585
+ }
586
+ }
587
+ }
588
+ export function _getAnchorTagValue(store) {
589
+ let href = "";
590
+ if (store.cursorData !== null) {
591
+ const $element = _findContentEditableElement(store.cursorData.startNode);
592
+ if ($element !== null) {
593
+ const cursorData = _soltingCursorDataOnElement(store.cursorData, $element);
594
+ if (cursorData.startNode.constructor.name === "HTMLAnchorElement") {
595
+ if (store.cursorData.type === "Range") {
596
+ if (cursorData.startNodeIdx !== cursorData.endNodeIdx) {
597
+ return href;
598
+ }
599
+ }
600
+ const $anchorTag = cursorData.startNode;
601
+ href = $anchorTag.href;
602
+ }
603
+ }
604
+ }
605
+ return href;
606
+ }
607
+ function findPoverTextNode(node, idx) {
608
+ if (node.previousSibling !== null) {
609
+ if (node.previousSibling.constructor.name === "Text") {
610
+ return findPoverTextNode(node.previousSibling, idx -= 1);
611
+ } else {
612
+ return idx;
613
+ }
614
+ } else {
615
+ return idx;
616
+ }
617
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dragon-editor",
3
- "version": "3.2.3",
3
+ "version": "3.4.0",
4
4
  "description": "Javascript WYSIWYG editor in Nuxt3!",
5
5
  "repository": {
6
6
  "type": "git",