leksy-editor 1.3.1 → 1.4.1
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 +2 -0
- package/constant.js +30 -5
- package/index.js +5 -7
- package/package.json +1 -1
- package/plugin.js +166 -42
- package/style.css +53 -0
- package/utilities.js +125 -9
package/README.md
CHANGED
|
@@ -99,12 +99,14 @@ const app = createApp({
|
|
|
99
99
|
| `tenorApiKey` | API key for Tenor integration. |
|
|
100
100
|
| `cssVariables` | Custom CSS styling variables for multiple themes and modes. |
|
|
101
101
|
| `disablePastedColorStyles` | Remove color-related CSS while pasting. |
|
|
102
|
+
| `removeColorsWhilePasting` | Remove all color and bg color CSS while pasting. |
|
|
102
103
|
| `autoHeight` | Automatically adjusts height based on content. |
|
|
103
104
|
| `height` | Height for the editor. |
|
|
104
105
|
| `maxHeight` | Maximum height for the editor. |
|
|
105
106
|
| `minHeight` | Minimum height for the editor. |
|
|
106
107
|
| `iframeStyle` | To design inside iframe, pass your css here |
|
|
107
108
|
| `disabled` | To disabled editor |
|
|
109
|
+
| `onFullScreen` | To open custom preview |
|
|
108
110
|
|
|
109
111
|
### CSS Customization
|
|
110
112
|
|
package/constant.js
CHANGED
|
@@ -27,6 +27,7 @@ const CLASSES = {
|
|
|
27
27
|
TOOLBAR_TABLE: '-toolbar-table',
|
|
28
28
|
TOOLBAR_ITEM: '-toolbar-item',
|
|
29
29
|
TOOLBAR_ITEM_SELECT: 'select',
|
|
30
|
+
TOOLBAR_ITEM_BUTTON_SELECT: 'button-select',
|
|
30
31
|
TOOLBAR_ITEM_COLOR: 'color',
|
|
31
32
|
TOOLBAR_ITEMS: '-toolbar-items',
|
|
32
33
|
PLACEHOLDER: '-placeholder',
|
|
@@ -49,6 +50,9 @@ const CLASSES = {
|
|
|
49
50
|
PREVIEW_MODAL_CONTENT: '-preview-modal-content',
|
|
50
51
|
PREVIEW_MODAL_CLOSE: '-preview-modal-close',
|
|
51
52
|
PREVIEW_MODAL_BODY: '-preview-modal-body',
|
|
53
|
+
UPLOAD_IMG_BOX: '-upload-img-box',
|
|
54
|
+
UPLOAD_IMG_PREVIEW_BOX: '-upload-img-preview-box',
|
|
55
|
+
UPLOAD_IMG_PREVIEW: '-upload-img-preview',
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
const SVG = {
|
|
@@ -66,6 +70,13 @@ const SVG = {
|
|
|
66
70
|
ATTACHMENT: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8.38 15.68"><g><path d="M15.23,6h1v9.78a3.88,3.88,0,0,1-1.31,2.45,4,4,0,0,1-6.57-2.45V7A3,3,0,0,1,9.2,4.89a3,3,0,0,1,5,2.09v8.31a1.92,1.92,0,0,1-.58,1.39,2,2,0,0,1-1.39.58,1.92,1.92,0,0,1-1.39-.58,2,2,0,0,1-.58-1.39V8h1v7.32a1,1,0,0,0,.29.69,1,1,0,0,0,.69.28A.9.9,0,0,0,13,16a1,1,0,0,0,.29-.69V7a1.92,1.92,0,0,0-.58-1.39A2,2,0,0,0,11.27,5a1.92,1.92,0,0,0-1.39.58A2,2,0,0,0,9.33,7v8.31a3,3,0,1,0,5.9,0V6Z" transform="translate(-8.08 -3.78)"/></g></svg>',
|
|
67
71
|
LIST_BULLETS: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.74 12.37"><g><path d="M7.77,16.12a1.59,1.59,0,0,0-.49-1.18,1.62,1.62,0,0,0-1.19-.49,1.68,1.68,0,1,0,0,3.36,1.67,1.67,0,0,0,1.68-1.69Zm0-4.48A1.67,1.67,0,0,0,6.09,10,1.68,1.68,0,0,0,4.9,12.82a1.62,1.62,0,0,0,1.19.49,1.67,1.67,0,0,0,1.68-1.67Zm12.38,3.64a.27.27,0,0,0-.08-.19.28.28,0,0,0-.2-.09H9.19a.28.28,0,0,0-.2.08.29.29,0,0,0-.08.19V17a.27.27,0,0,0,.28.28H19.87a.27.27,0,0,0,.19-.08.24.24,0,0,0,.08-.2V15.28ZM7.77,7.13a1.63,1.63,0,0,0-.49-1.2,1.61,1.61,0,0,0-1.19-.49,1.61,1.61,0,0,0-1.19.49,1.71,1.71,0,0,0,0,2.4,1.62,1.62,0,0,0,1.19.49,1.61,1.61,0,0,0,1.19-.49,1.63,1.63,0,0,0,.49-1.2Zm12.38,3.66a.28.28,0,0,0-.08-.2.29.29,0,0,0-.19-.08H9.19a.27.27,0,0,0-.28.28v1.69a.27.27,0,0,0,.08.19.24.24,0,0,0,.2.08H19.87a.27.27,0,0,0,.19-.08.25.25,0,0,0,.08-.19V10.79Zm0-4.5a.27.27,0,0,0-.08-.19A.25.25,0,0,0,19.88,6H9.19A.28.28,0,0,0,9,6.1a.26.26,0,0,0-.08.19V8A.27.27,0,0,0,9,8.17a.24.24,0,0,0,.2.08H19.87a.27.27,0,0,0,.19-.08A.25.25,0,0,0,20.14,8V6.29Z" transform="translate(-4.41 -5.44)"/></g></svg>',
|
|
68
72
|
LIST_NUMBER: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.69 15.74"><g><path d="M7.66,18a1.24,1.24,0,0,0-.26-.78,1.17,1.17,0,0,0-.72-.42l.85-1V15H4.58v1.34h.94v-.46l.85,0h0c-.11.11-.22.23-.32.35s-.23.27-.37.47L5.39,17l.23.51c.61-.05.92.11.92.49a.42.42,0,0,1-.18.37.79.79,0,0,1-.45.12A1.41,1.41,0,0,1,5,18.15l-.51.77A2.06,2.06,0,0,0,6,19.5a1.8,1.8,0,0,0,1.2-.41A1.38,1.38,0,0,0,7.66,18Zm0-5.54H6.75V13H5.63A.72.72,0,0,1,6,12.51a5.45,5.45,0,0,1,.66-.45,2.71,2.71,0,0,0,.67-.57,1.19,1.19,0,0,0,.31-.81,1.29,1.29,0,0,0-.45-1,1.86,1.86,0,0,0-2-.11,1.51,1.51,0,0,0-.62.7l.74.52A.87.87,0,0,1,6,10.28a.51.51,0,0,1,.35.12.42.42,0,0,1,.13.33.55.55,0,0,1-.21.4,3,3,0,0,1-.5.38c-.19.13-.39.27-.58.42a2,2,0,0,0-.5.6,1.63,1.63,0,0,0-.21.81,3.89,3.89,0,0,0,.05.48h3.2V12.44Zm12.45,2.82a.27.27,0,0,0-.08-.19.28.28,0,0,0-.21-.08H9.1a.32.32,0,0,0-.21.08.24.24,0,0,0-.08.2V17a.27.27,0,0,0,.08.19.3.3,0,0,0,.21.08H19.83a.32.32,0,0,0,.21-.08.25.25,0,0,0,.08-.19V15.26ZM7.69,7.32h-1V3.76H5.8L4.6,4.88l.63.68a1.85,1.85,0,0,0,.43-.48h0l0,2.24H4.74V8.2h3V7.32Zm12.43,3.42a.27.27,0,0,0-.08-.19.28.28,0,0,0-.21-.08H9.1a.32.32,0,0,0-.21.08.24.24,0,0,0-.08.2v1.71a.27.27,0,0,0,.08.19.3.3,0,0,0,.21.08H19.83a.32.32,0,0,0,.21-.08.25.25,0,0,0,.08-.19V10.74Zm0-4.52A.27.27,0,0,0,20,6,.28.28,0,0,0,19.83,6H9.1A.32.32,0,0,0,8.89,6a.24.24,0,0,0-.08.19V7.93a.27.27,0,0,0,.08.19.32.32,0,0,0,.21.08H19.83A.32.32,0,0,0,20,8.12a.26.26,0,0,0,.08-.2V6.22Z" transform="translate(-4.43 -3.76)"/></g></svg>',
|
|
73
|
+
NEW_LIST_NUMBER: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path d="M144,48V208a8,8,0,0,1-16,0V62.13L100.12,78.86a8,8,0,1,1-8.24-13.72l40-24A8,8,0,0,1,144,48Z"></path></svg>',
|
|
74
|
+
LIST_SQUARE: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path d="M224,48V208a16,16,0,0,1-16,16H48a16,16,0,0,1-16-16V48A16,16,0,0,1,48,32H208A16,16,0,0,1,224,48Z"></path></svg>',
|
|
75
|
+
LIST_DISC: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><rect x="32" y="32" width="192" height="192" rx="16"/></svg>',
|
|
76
|
+
LIST_CIRCLE: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><rect width="256" height="256" fill="none"/><circle cx="128" cy="128" r="96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/></svg>',
|
|
77
|
+
LIST_LOWER_ALPHA: '<svg viewBox="-6 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>a</title><path d="M15.969 12.094v-2.938h2.25v16.438h-2.25v-2.313c-1.563 1.719-3.875 2.844-6.438 2.844-4.75 0-8.906-3.75-8.906-8.438s4.156-8.438 8.906-8.438c2.563 0 4.875 1.125 6.438 2.844zM15.969 17.875v-0.375c-0.125-3.438-2.969-6.188-6.469-6.188-3.594 0-6.719 2.844-6.719 6.375s3.125 6.375 6.719 6.375c3.5 0 6.344-2.75 6.469-6.188z"></path></svg>',
|
|
78
|
+
LIST_LOWER_ROMAN: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><path d="M272 112C272 85.5 293.5 64 320 64C346.5 64 368 85.5 368 112C368 138.5 346.5 160 320 160C293.5 160 272 138.5 272 112zM224 256C224 238.3 238.3 224 256 224L320 224C337.7 224 352 238.3 352 256L352 512L384 512C401.7 512 416 526.3 416 544C416 561.7 401.7 576 384 576L256 576C238.3 576 224 561.7 224 544C224 526.3 238.3 512 256 512L288 512L288 288L256 288C238.3 288 224 273.7 224 256z"/></svg>',
|
|
79
|
+
LIST_UPPER_ALPHA: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><path d="M349.5 115.7C344.6 103.8 332.9 96 320 96C307.1 96 295.4 103.8 290.5 115.7C197.2 339.7 143.8 467.7 130.5 499.7C123.7 516 131.4 534.7 147.7 541.5C164 548.3 182.7 540.6 189.5 524.3L221.3 448L418.6 448L450.4 524.3C457.2 540.6 475.9 548.3 492.2 541.5C508.5 534.7 516.2 516 509.4 499.7C496.1 467.7 442.7 339.7 349.4 115.7zM392 384L248 384L320 211.2L392 384z"/></svg>',
|
|
69
80
|
SUBSCRIPT: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.75 14.61"><g><path d="M15.38,4.33H12.74L11.19,7c-.28.46-.51.87-.69,1.21L10.07,9h0l-.44-.8c-.22-.4-.45-.81-.71-1.23L7.34,4.33H4.68L8.26,10,4.4,16.08H7.1l1.69-2.83c.38-.63.72-1.22,1-1.78l.25-.46h0l.49.92c.24.45.48.89.74,1.32L13,16.08h2.61L11.84,10l1.77-2.84,1.77-2.85Zm4.77,13.75H17v-.15c0-.4.05-.64.16-.72a4.42,4.42,0,0,1,1.16-.31,3.3,3.3,0,0,0,1.54-.56A1.84,1.84,0,0,0,20.15,15a1.78,1.78,0,0,0-.44-1.41A2.8,2.8,0,0,0,18,13.25a2.71,2.71,0,0,0-1.69.37,1.83,1.83,0,0,0-.44,1.43v.23H17v-.23q0-.63.18-.78a1.62,1.62,0,0,1,.88-.15,1.59,1.59,0,0,1,.88.15q.18.15.18.75t-.18.75a3.58,3.58,0,0,1-1.18.33,3.33,3.33,0,0,0-1.52.51,1.57,1.57,0,0,0-.32,1.18v1.15h4.27v-.86Z" transform="translate(-4.4 -4.33)"/></g></svg>',
|
|
70
81
|
SUPERSCRIPT: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.75 15.42"><g><path d="M12,13.14l3.61-5.81H12.94L11.33,10c-.28.46-.51.88-.69,1.25l-.45.83h0l-.45-.85c-.22-.41-.45-.82-.71-1.24L7.4,7.33H4.68l3.66,5.81L4.4,19.33H7.14l1.74-2.87q.58-1,1-1.83l.25-.48h0l.51.94.75,1.37,1.72,2.87h2.67l-1.92-3.09c-1.12-1.8-1.76-2.83-1.92-3.1Zm4.84-4.41h0l0,.15h3.27v.86H15.77V8.58a1.66,1.66,0,0,1,.33-1.22,3.51,3.51,0,0,1,1.56-.51,3.68,3.68,0,0,0,1.21-.34c.13-.1.19-.36.19-.77S19,5.07,18.87,5A1.63,1.63,0,0,0,18,4.8a1.58,1.58,0,0,0-.91.17c-.13.11-.19.38-.19.8V6H15.78V5.76a1.87,1.87,0,0,1,.45-1.47A2.84,2.84,0,0,1,18,3.91a2.8,2.8,0,0,1,1.72.38,1.84,1.84,0,0,1,.45,1.44,1.91,1.91,0,0,1-.34,1.35,3.24,3.24,0,0,1-1.58.57A3.69,3.69,0,0,0,17,8c-.12.1-.17.35-.17.76Z" transform="translate(-4.4 -3.91)"/></g></svg>',
|
|
71
82
|
INDENT: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.74 12.36"><g><path d="M4.68,14.45a.27.27,0,0,1-.19-.08.3.3,0,0,1-.08-.21V9.1a.27.27,0,0,1,.08-.19.28.28,0,0,1,.2-.08.25.25,0,0,1,.19.07l2.54,2.54a.29.29,0,0,1,0,.4L4.88,14.36a.24.24,0,0,1-.2.09Zm15.19,1.12a.27.27,0,0,1,.19.08.25.25,0,0,1,.08.19v1.69a.27.27,0,0,1-.08.19.25.25,0,0,1-.19.08H4.68a.27.27,0,0,1-.19-.08.25.25,0,0,1-.08-.19V15.84a.27.27,0,0,1,.27-.27H19.87Zm0-3.38a.27.27,0,0,1,.19.08.28.28,0,0,1,.08.21v1.68a.32.32,0,0,1-.08.21.25.25,0,0,1-.19.08H10.31a.27.27,0,0,1-.19-.08.3.3,0,0,1-.08-.21V12.48a.32.32,0,0,1,.08-.21.24.24,0,0,1,.19-.08h9.56Zm0-3.37a.27.27,0,0,1,.19.08.25.25,0,0,1,.08.19v1.69a.27.27,0,0,1-.08.19.25.25,0,0,1-.19.08H10.31a.27.27,0,0,1-.27-.27V9.1a.27.27,0,0,1,.27-.27h9.56Zm.2-3.29a.28.28,0,0,1,.08.2V7.41a.32.32,0,0,1-.08.21.25.25,0,0,1-.19.08H4.68a.27.27,0,0,1-.19-.08.3.3,0,0,1-.08-.21V5.73a.32.32,0,0,1,.08-.21.25.25,0,0,1,.19-.08H19.87a.28.28,0,0,1,.2.09Z" transform="translate(-4.41 -5.44)"/></g></svg>',
|
|
@@ -88,6 +99,7 @@ const SVG = {
|
|
|
88
99
|
REVERT: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.76 14.69"><g><path d="M18.26,15V12.3l1.89-2V15a2.58,2.58,0,0,1-.24,1c-.2.58-.75.92-1.65,1H7.56v2L4.41,15.63,7.56,13v2h10.7ZM6.3,8.28V11L4.41,13V8.28a2.58,2.58,0,0,1,.24-1c.2-.58.75-.92,1.65-1H17v-2l3.15,3.34L17,10.3v-2H6.3Z" transform="translate(-4.4 -4.28)"/></g></svg>',
|
|
89
100
|
AUTO_SIZE: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.74 15.74"><g><path d="M6.71,17.19,6.89,16l1.21-.15A6,6,0,0,1,6.81,13.9a5.78,5.78,0,0,1-.45-2.27A6,6,0,0,1,8.1,7.45a5.83,5.83,0,0,1,4.17-1.73l1-1-1-1A7.89,7.89,0,0,0,5,14.64a7.73,7.73,0,0,0,1.71,2.55Zm5.57,2.31h0A7.86,7.86,0,0,0,17.85,6.07L17.67,7.3l-1.21.15a5.9,5.9,0,0,1,1.29,1.92,5.81,5.81,0,0,1,.45,2.26,5.91,5.91,0,0,1-5.9,5.9l-1,1,.49.49.47.5Z" transform="translate(-4.41 -3.76)"/></g></svg>',
|
|
90
101
|
ARROW_DOWN: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.73 8.67"><g><path d="M18.79,7.52a.8.8,0,0,1,.56-.23.82.82,0,0,1,.79.79.8.8,0,0,1-.23.56l-7.07,7.07a.79.79,0,0,1-.57.25.77.77,0,0,1-.57-.25h0L4.64,8.65a.8.8,0,0,1-.23-.57.82.82,0,0,1,.79-.79.8.8,0,0,1,.56.23L12.28,14l3.26-3.26,3.25-3.26Z" transform="translate(-4.41 -7.29)"/></g></svg>',
|
|
102
|
+
ARROW_DROP_DOWN_FILL: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" ><path d="M12 14L8 10H16L12 14Z"></path></svg>',
|
|
91
103
|
GIPHY_SVG: '<svg xmlns="http://www.w3.org/2000/svg" width="12px" viewBox="0 0 28 35"><g fill-rule="evenodd" clip-rule="evenodd"><path fill="#00ff99" d="M0 3h4v29H0z"></path><path fill="#9933ff" d="M24 11h4v21h-4z"></path><path fill="#00ccff" d="M0 31h28v4H0z"></path><path fill="#fff35c" d="M0 0h16v4H0z"></path><path fill="#ff6666" d="M24 8V4h-4V0h-4v12h12V8"></path><path class="shadow" d="M24 16v-4h4M16 0v4h-4"></path></g></svg>',
|
|
92
104
|
PEXELS: '<svg viewBox="0 0 17 22" fill="none" xmlns="http://www.w3.org/2000/svg"><g> <path fill-rule="evenodd" clip-rule="evenodd" d="M12 5C12.7111 5 13.3875 5.14845 14 5.41604C15.7659 6.1876 17 7.94968 17 10C17 12.0503 15.7659 13.8124 14 14.584C13.3875 14.8516 12.7111 15 12 15V19H6V5H12ZM8 7V17H10V13H12L12.0032 12.9988C13.6427 13.0303 15.0746 11.6934 15.0443 9.95469L15.0375 9.56529C15.0121 8.10183 13.7882 6.94549 12.3257 7.00299L12.0203 7.00762L12 7H8Z" fill="#07a081"></path> </g></svg>',
|
|
93
105
|
EMOJI: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10.5199 19.8634C10.5955 18.6615 10.8833 17.5172 11.3463 16.4676C9.81124 16.3252 8.41864 15.6867 7.33309 14.7151L8.66691 13.2248C9.55217 14.0172 10.7188 14.4978 12 14.4978C12.1763 14.4978 12.3501 14.4887 12.5211 14.471C14.227 12.2169 16.8661 10.7083 19.8634 10.5199C19.1692 6.80877 15.9126 4 12 4C7.58172 4 4 7.58172 4 12C4 15.9126 6.80877 19.1692 10.5199 19.8634ZM19.0233 12.636C15.7891 13.2396 13.2396 15.7891 12.636 19.0233L19.0233 12.636ZM22 12C22 12.1677 21.9959 12.3344 21.9877 12.5L12.5 21.9877C12.3344 21.9959 12.1677 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM10 10C10 10.8284 9.32843 11.5 8.5 11.5C7.67157 11.5 7 10.8284 7 10C7 9.17157 7.67157 8.5 8.5 8.5C9.32843 8.5 10 9.17157 10 10ZM17 10C17 10.8284 16.3284 11.5 15.5 11.5C14.6716 11.5 14 10.8284 14 10C14 9.17157 14.6716 8.5 15.5 8.5C16.3284 8.5 17 9.17157 17 10Z"></path></svg>',
|
|
@@ -130,10 +142,8 @@ const SVG = {
|
|
|
130
142
|
FULLSCREEN_IMAGE: '<svg xmlns="http://www.w3.org/2000/svg" width="20px" viewBox="0 0 24 24" fill="currentColor"><path d="M8 3V5H4V9H2V3H8ZM2 21V15H4V19H8V21H2ZM22 21H16V19H20V15H22V21ZM22 9H20V5H16V3H22V9Z"></path></svg>',
|
|
131
143
|
CLOSE: '<svg xmlns="http://www.w3.org/2000/svg" width="16px" viewBox="0 0 24 24" fill="currentColor"><path d="M10.5859 12L2.79297 4.20706L4.20718 2.79285L12.0001 10.5857L19.793 2.79285L21.2072 4.20706L13.4143 12L21.2072 19.7928L19.793 21.2071L12.0001 13.4142L4.20718 21.2071L2.79297 19.7928L10.5859 12Z"></path></svg>',
|
|
132
144
|
SPINNER: '<svg class="leksy-editor-spinner" width="16" height="16" viewBox="0 0 50 50"><circle class="leksy-editor-path" cx="25" cy="25" r="20" fill="none" stroke-width="4"></circle></svg>',
|
|
133
|
-
|
|
134
145
|
}
|
|
135
146
|
|
|
136
|
-
|
|
137
147
|
const MIMETYPE = {
|
|
138
148
|
IMAGE: 'image/png,image/jpg,image/jpeg,image/webp',
|
|
139
149
|
VIDEO: 'video/mp4,video/quicktime',
|
|
@@ -141,7 +151,6 @@ const MIMETYPE = {
|
|
|
141
151
|
|
|
142
152
|
const SOCIAL_MEDIA_PATTERNS = {
|
|
143
153
|
YOUTUBE: /(?:youtube\.com\/(?:.*[?&]v=|embed\/|v\/|watch\?v=|live\/)|youtu\.be\/)([^"&?\/\s]{11})/,
|
|
144
|
-
// TWITTER: /(?:twitter\.com\/(?:#!\/)?(?:\w+)\/status\/|x\.com\/(?:#!\/)?(?:\w+)\/status\/)(\d+)/,
|
|
145
154
|
REDDIT: /(?:reddit\.com\/r\/[\w-]+\/comments\/|reddit\.com\/comments\/)([\w-]+)/,
|
|
146
155
|
INSTAGRAM: /(?:instagram\.com\/(?:p|reel|tv|stories\/[\w-]+|[\w-]+\/posts|share\/p)\/|instagr\.am\/p\/)([\w-]+)/,
|
|
147
156
|
THREADS: /(?:threads\.net\/@[\w-]+\/post\/)([\w-]+)/,
|
|
@@ -154,7 +163,6 @@ const SOCIAL_MEDIA_PATTERNS = {
|
|
|
154
163
|
|
|
155
164
|
const SOCIAL_MEDIA_BASEURLS = {
|
|
156
165
|
YOUTUBE: "https://www.youtube.com/embed/",
|
|
157
|
-
// TWITTER: "https://twitframe.com/show?url=https://twitter.com/user/status/",
|
|
158
166
|
INSTAGRAM: "https://www.instagram.com/p/",
|
|
159
167
|
REDDIT: "https://www.redditmedia.com/r/all/comments/",
|
|
160
168
|
PINTEREST: "https://assets.pinterest.com/ext/embed.html?id=",
|
|
@@ -164,6 +172,7 @@ const SOCIAL_MEDIA_BASEURLS = {
|
|
|
164
172
|
TWITCH_CHANNEL: 'https://player.twitch.tv/?channel=',
|
|
165
173
|
TIKTOK: 'https://www.tiktok.com/embed/',
|
|
166
174
|
};
|
|
175
|
+
|
|
167
176
|
const CSS_VARIABLES = {
|
|
168
177
|
primary: "hsl(160, 100%, 40%)",
|
|
169
178
|
midDarker: "hsl(223, 5%, 76%)",
|
|
@@ -230,7 +239,8 @@ const CSS = {
|
|
|
230
239
|
`,
|
|
231
240
|
IFRAME_EDITOR: `
|
|
232
241
|
.content-editable {
|
|
233
|
-
height: 100vh;
|
|
242
|
+
min-height: 100vh;
|
|
243
|
+
height: 100%;
|
|
234
244
|
outline: 0;
|
|
235
245
|
padding: 4px;
|
|
236
246
|
box-sizing: border-box;
|
|
@@ -651,6 +661,19 @@ const TAB_CATEGORIES = {
|
|
|
651
661
|
}
|
|
652
662
|
};
|
|
653
663
|
|
|
664
|
+
const ORDERED_LIST_OPTIONS = {
|
|
665
|
+
'1': `${SVG.NEW_LIST_NUMBER} Number`,
|
|
666
|
+
'a': `${SVG.LIST_LOWER_ALPHA} Lower Alpha`,
|
|
667
|
+
'i': `${SVG.LIST_LOWER_ROMAN} Lower Roman`,
|
|
668
|
+
'A': `${SVG.LIST_UPPER_ALPHA} Upper Alpha`,
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const UNORDERED_LIST_OPTIONS = {
|
|
672
|
+
'Disc': `${SVG.LIST_DISC} Disc`,
|
|
673
|
+
'Circle': `${SVG.LIST_CIRCLE} Circle`,
|
|
674
|
+
'Square': `${SVG.LIST_SQUARE} Square`,
|
|
675
|
+
}
|
|
676
|
+
|
|
654
677
|
const RESIZE_MARGIN = 10;
|
|
655
678
|
|
|
656
679
|
const LIST_STYLES_BY_LEVEL = ['1', 'a', 'i', 'A'];
|
|
@@ -681,4 +704,6 @@ export {
|
|
|
681
704
|
RESIZE_MARGIN,
|
|
682
705
|
LIST_STYLES_BY_LEVEL,
|
|
683
706
|
UNORDERED_LIST_STYLES_BY_LEVEL,
|
|
707
|
+
UNORDERED_LIST_OPTIONS,
|
|
708
|
+
ORDERED_LIST_OPTIONS,
|
|
684
709
|
}
|
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './style.css'
|
|
2
2
|
import { CLASSES, CSS, CSS_VARIABLES, ERRORS, REGEX, SVG } from "./constant"
|
|
3
3
|
import PLUGINS, { applyTextFormat } from './plugin';
|
|
4
|
-
import { showAnchorPopover, changeAllToolbarState, changeToolbarStateByName, changeToolbarValueByName, cleanHTML, debounce, destroyImageResizer, destroyTableEditPlugin, initImageResizer, initTableEditPlugin, makeToolbarButton, makeToolbarColor, makeToolbarDropdown, makeToolbarSelect, rgbToHex, updateTableResizerPosition, destroyAnchorPopover, changeToolbarHtmlByName, showRemoteCursor, syncRemoteChangesDebounce, applyRemoteChanges, updateCursorPositionDebounce, buildTributeValues, updateHeight, getTableGrid, getCellPosition, makeUnorderedList, makeOrderedList, makeHeading, makeBlockQuote, makeStrikethrough, makeCodeBlock, makeSublist, showTooltip } from './utilities';
|
|
4
|
+
import { showAnchorPopover, changeAllToolbarState, changeToolbarStateByName, changeToolbarValueByName, cleanHTML, debounce, destroyImageResizer, destroyTableEditPlugin, initImageResizer, initTableEditPlugin, makeToolbarButton, makeToolbarColor, makeToolbarDropdown, makeToolbarSelect, rgbToHex, updateTableResizerPosition, destroyAnchorPopover, changeToolbarHtmlByName, showRemoteCursor, syncRemoteChangesDebounce, applyRemoteChanges, updateCursorPositionDebounce, buildTributeValues, updateHeight, getTableGrid, getCellPosition, makeUnorderedList, makeOrderedList, makeHeading, makeBlockQuote, makeStrikethrough, makeCodeBlock, makeSublist, showTooltip, makeToolbarButtonSelect } from './utilities';
|
|
5
5
|
|
|
6
6
|
class LeksyEditor {
|
|
7
7
|
|
|
@@ -21,12 +21,14 @@ class LeksyEditor {
|
|
|
21
21
|
* @property {String} tenorApiKey
|
|
22
22
|
* @property {Object} cssVariables
|
|
23
23
|
* @property {Boolean} disablePastedColorStyles
|
|
24
|
+
* @property {Boolean} removeColorsWhilePasting
|
|
24
25
|
* @property {Boolean} autoHeight
|
|
25
26
|
* @property {String} height
|
|
26
27
|
* @property {String} maxHeight
|
|
27
28
|
* @property {String} minHeight
|
|
28
29
|
* @property {String} iframeStyle
|
|
29
30
|
* @property {Boolean} disabled
|
|
31
|
+
* @property {Function} onFullScreen
|
|
30
32
|
*/
|
|
31
33
|
/**
|
|
32
34
|
*
|
|
@@ -263,7 +265,6 @@ class LeksyEditor {
|
|
|
263
265
|
getCore: () => core,
|
|
264
266
|
updateHeight: (height) => {
|
|
265
267
|
core.elements.iframeContainer.style.setProperty('height', height);
|
|
266
|
-
core.elements.editor.style.setProperty('height', height);
|
|
267
268
|
},
|
|
268
269
|
setDisabled: (disabled) => {
|
|
269
270
|
options.disabled = disabled;
|
|
@@ -371,6 +372,8 @@ class LeksyEditor {
|
|
|
371
372
|
toolbarPlugin = makeToolbarSelect(_plugin, options, core)
|
|
372
373
|
} else if (_plugin.type === 'color') {
|
|
373
374
|
toolbarPlugin = makeToolbarColor(_plugin, options, core)
|
|
375
|
+
} else if (_plugin.type === 'button-select') {
|
|
376
|
+
toolbarPlugin = makeToolbarButtonSelect(_plugin, options, core)
|
|
374
377
|
}
|
|
375
378
|
if (core.elements.toolbar[plugin])
|
|
376
379
|
core.elements.toolbar[plugin].push(toolbarPlugin)
|
|
@@ -609,11 +612,6 @@ class LeksyEditor {
|
|
|
609
612
|
contentEditableDiv.spellcheck = !!options.spellcheck
|
|
610
613
|
contentEditableDiv.innerHTML = core.html;
|
|
611
614
|
contentEditableDiv.className = 'content-editable';
|
|
612
|
-
if (options.autoHeight) contentEditableDiv.style.height = 'auto';
|
|
613
|
-
else contentEditableDiv.style.height = options.minHeight ?? options.height ?? '250px';
|
|
614
|
-
contentEditableDiv.style.minHeight = options.minHeight ?? options.height ?? '250px';
|
|
615
|
-
if (options.maxHeight) contentEditableDiv.style.maxHeight = options.maxHeight;
|
|
616
|
-
if (options.autoHeight) iframe.contentDocument.body.style.overflow = 'hidden';
|
|
617
615
|
|
|
618
616
|
contentEditableDiv.oninput = (e) => {
|
|
619
617
|
core.onChange(e.target.innerHTML)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leksy-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Leksy Editor is an alternative to traditional WYSIWYG editors, designed primarily for creating mail templates, blogs, and documents without any content manipulation.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
package/plugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { EMOJI_CATEGORIES, FONT_SIZE_OPTIONS, FONTS, FORMAT_OPTIONS, MIMETYPE, REGEX, SPECIAL_CHARACTERS, SVG } from "./constant"
|
|
1
|
+
import { EMOJI_CATEGORIES, FONT_SIZE_OPTIONS, FONTS, FORMAT_OPTIONS, MIMETYPE, REGEX, SPECIAL_CHARACTERS, SVG, UNORDERED_LIST_OPTIONS, ORDERED_LIST_OPTIONS, CLASSES } from "./constant"
|
|
2
2
|
import { giphy, pexels, tenor } from "./gallery";
|
|
3
|
-
import { formatLink, changeAllToolbarState, changeToolbarHtmlByName, changeToolbarStateByName, changeToolbarValueByName, cleanHTML, constructEmbedUrl, extractSocialMediaId, isLinkValid, openModal } from "./utilities";
|
|
3
|
+
import { formatLink, changeAllToolbarState, changeToolbarHtmlByName, changeToolbarStateByName, changeToolbarValueByName, cleanHTML, constructEmbedUrl, extractSocialMediaId, isLinkValid, openModal, transformTextStyle } from "./utilities";
|
|
4
4
|
|
|
5
5
|
const applyTextFormat = (core, command) => {
|
|
6
6
|
core.elements.editor.focus();
|
|
@@ -267,23 +267,62 @@ const PLUGINS = {
|
|
|
267
267
|
'ordered_list': {
|
|
268
268
|
title: "Ordered List",
|
|
269
269
|
icon: SVG.LIST_NUMBER,
|
|
270
|
-
type: 'button',
|
|
271
|
-
|
|
270
|
+
type: 'button-select',
|
|
271
|
+
options: Object.keys(ORDERED_LIST_OPTIONS).map(list => ({
|
|
272
|
+
label: ORDERED_LIST_OPTIONS[list], value: list
|
|
273
|
+
})),
|
|
274
|
+
click: (value, core, options) => {
|
|
272
275
|
core.elements.editor.focus();
|
|
273
|
-
core.elements.iframeWindow.execCommand('insertOrderedList');
|
|
274
|
-
core.updateCaretPosition()
|
|
275
|
-
|
|
276
276
|
const isActive = core.elements.iframeWindow.queryCommandState('insertOrderedList');
|
|
277
|
-
if (isActive)
|
|
278
|
-
|
|
277
|
+
if (!isActive) {
|
|
278
|
+
core.elements.iframeWindow.execCommand('insertOrderedList');
|
|
279
|
+
}
|
|
280
|
+
const selection = core.elements.iframeWindow.getSelection();
|
|
281
|
+
if (selection.rangeCount > 0) {
|
|
282
|
+
let node = selection.anchorNode;
|
|
283
|
+
while (node && node.nodeName !== 'OL' && node !== core.elements.editor) {
|
|
284
|
+
node = node.parentNode;
|
|
285
|
+
}
|
|
286
|
+
if (node?.nodeName === 'OL') {
|
|
287
|
+
node.setAttribute('type', value);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
core.updateCaretPosition()
|
|
291
|
+
changeToolbarStateByName(core, 'active', ['ordered_list'])
|
|
279
292
|
changeToolbarStateByName(core, 'inactive', ['unordered_list'])
|
|
293
|
+
},
|
|
294
|
+
mainClick: (event, core, options) => {
|
|
295
|
+
applyOrderList(core)
|
|
280
296
|
}
|
|
281
297
|
},
|
|
282
298
|
'unordered_list': {
|
|
283
299
|
title: "Unordered List",
|
|
284
300
|
icon: SVG.LIST_BULLETS,
|
|
285
|
-
type: 'button',
|
|
286
|
-
|
|
301
|
+
type: 'button-select',
|
|
302
|
+
options: Object.keys(UNORDERED_LIST_OPTIONS).map(list => ({
|
|
303
|
+
label: UNORDERED_LIST_OPTIONS[list], value: list
|
|
304
|
+
})),
|
|
305
|
+
click: (value, core, options) => {
|
|
306
|
+
core.elements.editor.focus();
|
|
307
|
+
const isActive = core.elements.iframeWindow.queryCommandState('insertUnorderedList');
|
|
308
|
+
if (!isActive) {
|
|
309
|
+
core.elements.iframeWindow.execCommand('insertUnorderedList');
|
|
310
|
+
}
|
|
311
|
+
const selection = core.elements.iframeWindow.getSelection();
|
|
312
|
+
if (selection.rangeCount > 0) {
|
|
313
|
+
let node = selection.anchorNode;
|
|
314
|
+
while (node && node.nodeName !== 'UL' && node !== core.elements.editor) {
|
|
315
|
+
node = node.parentNode;
|
|
316
|
+
}
|
|
317
|
+
if (node?.nodeName === 'UL') {
|
|
318
|
+
node.style.listStyleType = value;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
core.updateCaretPosition()
|
|
322
|
+
changeToolbarStateByName(core, 'active', ['unordered_list'])
|
|
323
|
+
changeToolbarStateByName(core, 'inactive', ['ordered_list'])
|
|
324
|
+
},
|
|
325
|
+
mainClick: (event, core, options) => {
|
|
287
326
|
applyUnorderedList(core)
|
|
288
327
|
}
|
|
289
328
|
},
|
|
@@ -388,7 +427,12 @@ const PLUGINS = {
|
|
|
388
427
|
{ label: 'Block Quote', value: 'blockquote' },
|
|
389
428
|
{ label: 'Code', value: 'code' },
|
|
390
429
|
{ label: 'Translucent', value: 'translucent' },
|
|
391
|
-
{ label: 'Shadow', value: 'shadow' }
|
|
430
|
+
{ label: 'Shadow', value: 'shadow' },
|
|
431
|
+
{ label: 'Upper Case', value: 'upper_case' },
|
|
432
|
+
{ label: 'Lower Case', value: 'lower_case' },
|
|
433
|
+
{ label: 'Title Case', value: 'title_case' },
|
|
434
|
+
{ label: 'Button (Green)', value: 'button_green' },
|
|
435
|
+
{ label: 'Button (Black)', value: 'button_black' }
|
|
392
436
|
],
|
|
393
437
|
click: (event, core, options) => {
|
|
394
438
|
if (!core.state.range) return
|
|
@@ -423,6 +467,50 @@ const PLUGINS = {
|
|
|
423
467
|
core.state.range.insertNode(code);
|
|
424
468
|
break;
|
|
425
469
|
}
|
|
470
|
+
case 'upper_case': {
|
|
471
|
+
transformTextStyle(core, 'upper_case');
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
case 'lower_case': {
|
|
475
|
+
transformTextStyle(core, 'lower_case');
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
case 'title_case': {
|
|
479
|
+
transformTextStyle(core, 'title_case');
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
case 'button_green': {
|
|
483
|
+
core.updateCaretPosition()
|
|
484
|
+
const span = document.createElement('span');
|
|
485
|
+
span.textContent = core.state.range.toString();
|
|
486
|
+
span.style.cssText = 'background-color: #28a745; color: white; font-weight: bold; padding: 8px; border-radius: 4px; text-decoration: none; display: inline-block; cursor: pointer;';
|
|
487
|
+
span.contentEditable = 'false';
|
|
488
|
+
let element = core.state.range.commonAncestorContainer;
|
|
489
|
+
if (element.nodeType === Node.TEXT_NODE) element = element.parentElement;
|
|
490
|
+
if (element.nodeName === 'A') {
|
|
491
|
+
element.style.cssText = 'background-color: #28a745; color: white; font-weight: bold; padding: 8px; border-radius: 4px; text-decoration: none; display: inline-block; cursor: pointer;';
|
|
492
|
+
} else if (span.textContent && !['TR', 'TBODY', 'THEAD', 'TABLE'].includes(element.nodeName)) {
|
|
493
|
+
core.state.range.deleteContents();
|
|
494
|
+
core.state.range.insertNode(span);
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
case 'button_black': {
|
|
499
|
+
core.updateCaretPosition()
|
|
500
|
+
const span = document.createElement('span');
|
|
501
|
+
span.textContent = core.state.range.toString();
|
|
502
|
+
span.style.cssText = 'background-color: black; color: white; font-weight: bold; padding: 8px; border-radius: 4px; text-decoration: none; display: inline-block; cursor: pointer;';
|
|
503
|
+
span.contentEditable = 'false';
|
|
504
|
+
let element = core.state.range.commonAncestorContainer;
|
|
505
|
+
if (element.nodeType === Node.TEXT_NODE) element = element.parentElement;
|
|
506
|
+
if (element.nodeName === 'A') {
|
|
507
|
+
element.style.cssText = 'background-color: black; color: white; font-weight: bold; padding: 8px; border-radius: 4px; text-decoration: none; display: inline-block; cursor: pointer;';
|
|
508
|
+
} else if (span.textContent && !['TR', 'TBODY', 'THEAD', 'TABLE'].includes(element.nodeName)) {
|
|
509
|
+
core.state.range.deleteContents();
|
|
510
|
+
core.state.range.insertNode(span);
|
|
511
|
+
}
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
426
514
|
}
|
|
427
515
|
core.elements.editor.focus();
|
|
428
516
|
core.updateCaretPosition()
|
|
@@ -742,53 +830,85 @@ const PLUGINS = {
|
|
|
742
830
|
button.click();
|
|
743
831
|
}
|
|
744
832
|
};
|
|
745
|
-
const body = document.createElement('div');
|
|
746
833
|
|
|
834
|
+
// Top
|
|
835
|
+
const top = document.createElement('div');
|
|
836
|
+
top.style.display = 'flex';
|
|
837
|
+
top.style.gap = '16px';
|
|
838
|
+
|
|
839
|
+
// Top - left
|
|
840
|
+
const left = document.createElement('div');
|
|
841
|
+
left.style.display = 'flex';
|
|
842
|
+
left.style.flexDirection = 'column';
|
|
843
|
+
left.style.gap = '16px';
|
|
844
|
+
left.style.flex = '1';
|
|
845
|
+
|
|
846
|
+
const uploadBox = document.createElement('div');
|
|
847
|
+
uploadBox.className = `${options.classPrefix}${CLASSES.UPLOAD_IMG_BOX}`;
|
|
848
|
+
uploadBox.innerHTML = `
|
|
849
|
+
<div style="text-align: center; color: #6b7280;">
|
|
850
|
+
<div style="font-size: 32px; font-weight: 500;">+</div>
|
|
851
|
+
<div style="font-size: 14px;">Click to browse files</div>
|
|
852
|
+
</div>
|
|
853
|
+
`;
|
|
747
854
|
|
|
748
855
|
const fileInput = document.createElement('input');
|
|
749
856
|
fileInput.type = 'file';
|
|
750
857
|
fileInput.accept = MIMETYPE.IMAGE;
|
|
751
858
|
fileInput.style.display = 'none';
|
|
859
|
+
uploadBox.addEventListener('click', () => fileInput.click());
|
|
752
860
|
|
|
753
|
-
|
|
754
|
-
const uploadBtn = document.createElement('button');
|
|
755
|
-
uploadBtn.innerText = 'Choose Image';
|
|
756
|
-
uploadBtn.type = 'button';
|
|
757
|
-
uploadBtn.style.border = '1px solid grey';
|
|
758
|
-
uploadBtn.style.padding = '4px';
|
|
759
|
-
uploadBtn.style.borderRadius = '6px';
|
|
861
|
+
left.append(uploadBox, fileInput);
|
|
760
862
|
|
|
863
|
+
// Top - right
|
|
864
|
+
const right = document.createElement('div');
|
|
865
|
+
right.style.display = 'flex';
|
|
866
|
+
right.style.flexDirection = 'column';
|
|
867
|
+
right.style.flex = '1';
|
|
761
868
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
fileNameSpan.style.marginLeft = '10px';
|
|
765
|
-
fileNameSpan.innerText = 'No file selected';
|
|
869
|
+
const previewBox = document.createElement('div');
|
|
870
|
+
previewBox.className = `${options.classPrefix}${CLASSES.UPLOAD_IMG_PREVIEW_BOX}`;
|
|
766
871
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
872
|
+
const imgPreview = document.createElement('img');
|
|
873
|
+
imgPreview.className = `${options.classPrefix}${CLASSES.UPLOAD_IMG_PREVIEW}`;
|
|
874
|
+
imgPreview.style.display = 'none';
|
|
875
|
+
|
|
876
|
+
previewBox.append(imgPreview);
|
|
877
|
+
right.append(previewBox);
|
|
878
|
+
|
|
879
|
+
// Complete top
|
|
880
|
+
top.append(left, right)
|
|
770
881
|
|
|
771
|
-
|
|
772
|
-
|
|
882
|
+
// other fields
|
|
883
|
+
const span = document.createElement('div');
|
|
884
|
+
span.className = 'warning';
|
|
885
|
+
|
|
886
|
+
const altLabel = document.createElement('label');
|
|
887
|
+
altLabel.innerText = 'Image Description (Alt Text)';
|
|
773
888
|
altLabel.style.display = "block";
|
|
774
889
|
altLabel.style.paddingLeft = "4px";
|
|
775
|
-
altLabel.style.marginTop = '
|
|
890
|
+
altLabel.style.marginTop = '4px';
|
|
891
|
+
altLabel.style.marginBottom = '4px';
|
|
776
892
|
|
|
777
893
|
const altInput = document.createElement('input');
|
|
778
894
|
altInput.type = 'text';
|
|
779
895
|
altInput.placeholder = 'Alternative Text';
|
|
780
896
|
altInput.addEventListener('keydown', onInputKeydown);
|
|
781
897
|
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
body.append(fileInput, uploadBtn, fileNameSpan, altLabel, altInput, span);
|
|
898
|
+
const body = document.createElement('div');
|
|
899
|
+
body.append(top, span, altLabel, altInput);
|
|
786
900
|
|
|
901
|
+
// Footer
|
|
787
902
|
const footer = document.createElement('div');
|
|
903
|
+
footer.style.display = 'flex';
|
|
904
|
+
footer.style.justifyContent = 'space-between';
|
|
905
|
+
footer.style.alignItems = 'center';
|
|
906
|
+
|
|
788
907
|
const button = document.createElement('button');
|
|
789
908
|
button.type = 'button';
|
|
790
909
|
button.className = 'submit';
|
|
791
910
|
button.innerText = 'Add';
|
|
911
|
+
|
|
792
912
|
footer.append(button);
|
|
793
913
|
|
|
794
914
|
const modal = openModal(
|
|
@@ -800,33 +920,35 @@ const PLUGINS = {
|
|
|
800
920
|
core,
|
|
801
921
|
options
|
|
802
922
|
);
|
|
803
|
-
let base64String =
|
|
923
|
+
let base64String = '';
|
|
804
924
|
|
|
805
925
|
fileInput.addEventListener('change', (event) => {
|
|
806
926
|
const file = event.target.files[0];
|
|
807
|
-
|
|
808
927
|
if (file && MIMETYPE.IMAGE.includes(file.type)) {
|
|
809
928
|
const reader = new FileReader();
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
929
|
+
reader.onload = () => {
|
|
930
|
+
base64String = reader.result;
|
|
931
|
+
imgPreview.src = base64String;
|
|
932
|
+
imgPreview.style.display = 'block';
|
|
813
933
|
};
|
|
814
|
-
|
|
815
934
|
reader.readAsDataURL(file);
|
|
816
|
-
|
|
817
|
-
span.innerText = ""; // Clear warning if file is selected
|
|
935
|
+
span.innerText = "";
|
|
818
936
|
}
|
|
819
937
|
});
|
|
938
|
+
|
|
820
939
|
fileInput.addEventListener('click', async () => {
|
|
821
940
|
let fileFromNative = await core.handleFilePicker(MIMETYPE.IMAGE.split(','), 'image');
|
|
822
941
|
|
|
823
942
|
if (fileFromNative) {
|
|
824
943
|
base64String = fileFromNative.data;
|
|
825
944
|
fileNameSpan.innerText = fileFromNative.name;
|
|
945
|
+
imgPreview.src = base64String;
|
|
946
|
+
imgPreview.style.display = 'block';
|
|
826
947
|
span.innerText = ""; // Clear warning if file is selected
|
|
827
948
|
|
|
828
949
|
}
|
|
829
950
|
});
|
|
951
|
+
|
|
830
952
|
button.onclick = async () => {
|
|
831
953
|
if (!base64String) {
|
|
832
954
|
span.innerText = 'Image not selected';
|
|
@@ -843,6 +965,7 @@ const PLUGINS = {
|
|
|
843
965
|
core.insertNode(img);
|
|
844
966
|
modal.close();
|
|
845
967
|
};
|
|
968
|
+
|
|
846
969
|
}
|
|
847
970
|
else if (event.target.getAttribute('data-value') === 'link') {
|
|
848
971
|
const onInputKeydown = (event) => {
|
|
@@ -1204,6 +1327,7 @@ const PLUGINS = {
|
|
|
1204
1327
|
core.updateCaretPosition()
|
|
1205
1328
|
}
|
|
1206
1329
|
}
|
|
1330
|
+
|
|
1207
1331
|
}
|
|
1208
1332
|
|
|
1209
1333
|
export default PLUGINS
|
package/style.css
CHANGED
|
@@ -119,6 +119,23 @@
|
|
|
119
119
|
width: unset;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
.leksy-editor-toolbar-item.button-select {
|
|
123
|
+
border-radius: 4px 0 0 4px;
|
|
124
|
+
margin-right: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.leksy-editor-toolbar-item.select.button-select {
|
|
128
|
+
padding: 0;
|
|
129
|
+
border-radius: 0 4px 4px 0;
|
|
130
|
+
margin-left: 0;
|
|
131
|
+
margin-right: 1px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.leksy-editor-toolbar-item.select.button-select svg {
|
|
135
|
+
width: 18px;
|
|
136
|
+
height: 18px;
|
|
137
|
+
}
|
|
138
|
+
|
|
122
139
|
.leksy-editor-toolbar-item.reset-color {
|
|
123
140
|
width: unset;
|
|
124
141
|
padding: 4px 8px;
|
|
@@ -277,6 +294,11 @@
|
|
|
277
294
|
border-radius: 6px;
|
|
278
295
|
}
|
|
279
296
|
|
|
297
|
+
.leksy-editor-dropdown-content>button svg {
|
|
298
|
+
width: 10px;
|
|
299
|
+
margin-right: 2px;
|
|
300
|
+
}
|
|
301
|
+
|
|
280
302
|
.leksy-editor-dropdown-content>button:hover {
|
|
281
303
|
background-color: #28a745;
|
|
282
304
|
color: #fff;
|
|
@@ -599,6 +621,37 @@ button.leksy-editor-popover-tab.active {
|
|
|
599
621
|
animation: leksy-editor-dash 1.5s ease-in-out infinite;
|
|
600
622
|
}
|
|
601
623
|
|
|
624
|
+
.leksy-editor-upload-img-box {
|
|
625
|
+
height: 180px;
|
|
626
|
+
border: 2px dashed #d1d5db;
|
|
627
|
+
border-radius: 12px;
|
|
628
|
+
background: #f9fafb;
|
|
629
|
+
display: flex;
|
|
630
|
+
align-items: center;
|
|
631
|
+
justify-content: center;
|
|
632
|
+
cursor: pointer;
|
|
633
|
+
transition: border-color 0.2s ease;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.leksy-editor-upload-img-box:hover {
|
|
637
|
+
border-color: gray;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.leksy-editor-upload-img-preview-box {
|
|
641
|
+
height: 180px;
|
|
642
|
+
border: 2px solid grey;
|
|
643
|
+
margin-bottom: 8px;
|
|
644
|
+
border-radius: 8px;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.leksy-editor-upload-img-preview {
|
|
648
|
+
width: 100%;
|
|
649
|
+
height: 100%;
|
|
650
|
+
border-radius: 8px;
|
|
651
|
+
object-fit: cover;
|
|
652
|
+
object-position: top;
|
|
653
|
+
}
|
|
654
|
+
|
|
602
655
|
@keyframes leksy-editor-rotate {
|
|
603
656
|
100% {
|
|
604
657
|
transform: rotate(360deg);
|
package/utilities.js
CHANGED
|
@@ -45,6 +45,10 @@ const traverseAndClean = (element, options, core) => {
|
|
|
45
45
|
if (bodyBg === bgColor) node.style.removeProperty('background-color');
|
|
46
46
|
if (bodyBg === textColor) node.style.removeProperty('color');
|
|
47
47
|
}
|
|
48
|
+
if (options?.removeColorsWhilePasting) {
|
|
49
|
+
node.style.removeProperty('background-color');
|
|
50
|
+
node.style.removeProperty('color');
|
|
51
|
+
}
|
|
48
52
|
attributesToRemove.forEach(attr => node.removeAttribute(attr));
|
|
49
53
|
|
|
50
54
|
// Process child nodes
|
|
@@ -197,11 +201,38 @@ const makeToolbarButton = (_plugin, options, core) => {
|
|
|
197
201
|
return pluginButton
|
|
198
202
|
}
|
|
199
203
|
|
|
204
|
+
|
|
205
|
+
const makeToolbarButtonSelect = (_plugin, options, core) => {
|
|
206
|
+
const pluginButton = document.createElement('button');
|
|
207
|
+
pluginButton.type = "button"
|
|
208
|
+
pluginButton.className = `${options.classPrefix}${CLASSES.TOOLBAR_ITEM} ${_plugin.type === 'button-select' ? CLASSES.TOOLBAR_ITEM_BUTTON_SELECT : ''}`
|
|
209
|
+
|
|
210
|
+
pluginButton.dataset.title = _plugin.title
|
|
211
|
+
pluginButton.dataset.type = 'button'
|
|
212
|
+
pluginButton.onclick = (e) => {
|
|
213
|
+
e.preventDefault();
|
|
214
|
+
_plugin.mainClick(e, core, options);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const pluginIcon = document.createElement('div');
|
|
218
|
+
pluginIcon.innerHTML = _plugin.icon;
|
|
219
|
+
pluginButton.appendChild(pluginIcon)
|
|
220
|
+
const pluginSelect = makeToolbarSelect({ ..._plugin, icon: '' }, options, core);
|
|
221
|
+
|
|
222
|
+
const pluginButtonSelect = document.createElement('div');
|
|
223
|
+
pluginButtonSelect.dataset.type = 'button-select'
|
|
224
|
+
pluginButtonSelect.style.display = 'flex'
|
|
225
|
+
pluginButtonSelect.appendChild(pluginButton);
|
|
226
|
+
pluginButtonSelect.appendChild(pluginSelect);
|
|
227
|
+
return pluginButtonSelect
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
200
231
|
const makeToolbarColor = (_plugin, options, core) => {
|
|
201
232
|
const pluginContainer = document.createElement('div');
|
|
202
233
|
pluginContainer.className = `${options.classPrefix}${CLASSES.TOOLBAR_ITEM} ${CLASSES.TOOLBAR_ITEM_COLOR}`
|
|
203
|
-
pluginContainer.
|
|
204
|
-
pluginContainer.
|
|
234
|
+
pluginContainer.dataset.title = _plugin.title
|
|
235
|
+
pluginContainer.dataset.type = 'color'
|
|
205
236
|
|
|
206
237
|
const pluginButton = document.createElement('input');
|
|
207
238
|
pluginButton.type = "color"
|
|
@@ -531,23 +562,29 @@ const makeToolbarSelect = (_plugin, options, core) => {
|
|
|
531
562
|
}
|
|
532
563
|
|
|
533
564
|
const selectPlugin = document.createElement('div');
|
|
534
|
-
selectPlugin.
|
|
565
|
+
selectPlugin.dataset.type = 'select'
|
|
535
566
|
|
|
536
567
|
const dropdownButton = document.createElement('button');
|
|
537
568
|
dropdownButton.type = "button"
|
|
538
|
-
dropdownButton.className = `${options.classPrefix}${CLASSES.TOOLBAR_ITEM} ${CLASSES.TOOLBAR_ITEM_SELECT}`
|
|
539
|
-
dropdownButton.
|
|
569
|
+
dropdownButton.className = `${options.classPrefix}${CLASSES.TOOLBAR_ITEM} ${CLASSES.TOOLBAR_ITEM_SELECT} ${_plugin.type === 'button-select' ? CLASSES.TOOLBAR_ITEM_BUTTON_SELECT : ''}`
|
|
570
|
+
dropdownButton.dataset.title = _plugin.type == 'button-select' ? `Options` : _plugin.title
|
|
540
571
|
|
|
541
572
|
const pluginIcon = document.createElement('div');
|
|
542
573
|
pluginIcon.style.width = _plugin.width
|
|
543
574
|
pluginIcon.style.textAlign = 'left'
|
|
544
575
|
pluginIcon.style.display = 'flex'
|
|
545
576
|
pluginIcon.style.justifyContent = 'space-between'
|
|
577
|
+
|
|
546
578
|
const iconName = document.createElement('span');
|
|
547
579
|
iconName.innerHTML = _plugin.icon;
|
|
580
|
+
|
|
548
581
|
const arrow = document.createElement('span');
|
|
549
|
-
|
|
550
|
-
|
|
582
|
+
if (_plugin.type == 'button-select') {
|
|
583
|
+
arrow.innerHTML = SVG.ARROW_DROP_DOWN_FILL;
|
|
584
|
+
} else {
|
|
585
|
+
arrow.innerHTML = SVG.ARROW_DOWN;
|
|
586
|
+
arrow.style.paddingLeft = '8px';
|
|
587
|
+
}
|
|
551
588
|
pluginIcon.append(iconName, arrow)
|
|
552
589
|
|
|
553
590
|
dropdownButton.append(pluginIcon)
|
|
@@ -908,7 +945,7 @@ const makeEditToolbar = (options, core, { type, td, image, updateImage, updateTa
|
|
|
908
945
|
title.textContent = plugin.title;
|
|
909
946
|
|
|
910
947
|
const input = document.createElement('input');
|
|
911
|
-
input.type = "
|
|
948
|
+
input.type = "number";
|
|
912
949
|
input.placeholder = "auto";
|
|
913
950
|
input.style.width = '60px';
|
|
914
951
|
input.style.padding = '2px';
|
|
@@ -1128,7 +1165,11 @@ const initImageResizer = (type, image, options, core) => {
|
|
|
1128
1165
|
src = href;
|
|
1129
1166
|
}
|
|
1130
1167
|
}
|
|
1131
|
-
|
|
1168
|
+
if (options.onFullScreen instanceof Function) {
|
|
1169
|
+
const type = isVideo ? 'video/mp4' : 'image/png';
|
|
1170
|
+
options.onFullScreen(src, type);
|
|
1171
|
+
}
|
|
1172
|
+
else createPreviewModal(src, core, options, isVideo);
|
|
1132
1173
|
});
|
|
1133
1174
|
|
|
1134
1175
|
resizer.appendChild(fullscreenButton);
|
|
@@ -2018,6 +2059,11 @@ const changeToolbarStatByPlugin = (plugin, action, value) => {
|
|
|
2018
2059
|
} else if (plugin.getAttribute('data-type') === 'color') {
|
|
2019
2060
|
plugin.childNodes[0].disabled = true
|
|
2020
2061
|
plugin.classList.add('disabled')
|
|
2062
|
+
} else if (plugin.getAttribute('data-type') === 'button-select') {
|
|
2063
|
+
plugin.querySelectorAll('button').forEach(btn => {
|
|
2064
|
+
btn.disabled = true
|
|
2065
|
+
btn.classList.add('disabled')
|
|
2066
|
+
})
|
|
2021
2067
|
}
|
|
2022
2068
|
break;
|
|
2023
2069
|
case 'enabled':
|
|
@@ -2030,6 +2076,11 @@ const changeToolbarStatByPlugin = (plugin, action, value) => {
|
|
|
2030
2076
|
} else if (plugin.getAttribute('data-type') === 'color') {
|
|
2031
2077
|
plugin.childNodes[0].disabled = false
|
|
2032
2078
|
plugin.classList.remove('disabled')
|
|
2079
|
+
} else if (plugin.getAttribute('data-type') === 'button-select') {
|
|
2080
|
+
plugin.querySelectorAll('button').forEach(btn => {
|
|
2081
|
+
btn.disabled = false
|
|
2082
|
+
btn.classList.remove('disabled')
|
|
2083
|
+
})
|
|
2033
2084
|
}
|
|
2034
2085
|
break;
|
|
2035
2086
|
case 'active':
|
|
@@ -2039,6 +2090,8 @@ const changeToolbarStatByPlugin = (plugin, action, value) => {
|
|
|
2039
2090
|
plugin.childNodes[0].classList.add('active')
|
|
2040
2091
|
} else if (plugin.getAttribute('data-type') === 'color') {
|
|
2041
2092
|
plugin.classList.add('active')
|
|
2093
|
+
} else if (plugin.getAttribute('data-type') === 'button-select') {
|
|
2094
|
+
plugin.querySelector('button[data-type="button"]')?.classList.add('active')
|
|
2042
2095
|
}
|
|
2043
2096
|
break;
|
|
2044
2097
|
case 'inactive':
|
|
@@ -2048,6 +2101,8 @@ const changeToolbarStatByPlugin = (plugin, action, value) => {
|
|
|
2048
2101
|
plugin.childNodes[0].classList.remove('active')
|
|
2049
2102
|
} else if (plugin.getAttribute('data-type') === 'color') {
|
|
2050
2103
|
plugin.classList.remove('active')
|
|
2104
|
+
} else if (plugin.getAttribute('data-type') === 'button-select') {
|
|
2105
|
+
plugin.querySelector('button[data-type="button"]')?.classList.remove('active')
|
|
2051
2106
|
}
|
|
2052
2107
|
break;
|
|
2053
2108
|
case 'font':
|
|
@@ -3073,6 +3128,65 @@ const makeSublist = (event, core) => {
|
|
|
3073
3128
|
}
|
|
3074
3129
|
};
|
|
3075
3130
|
|
|
3131
|
+
const transformCase = (text, type) => {
|
|
3132
|
+
if (type === 'upper_case') return text.toUpperCase();
|
|
3133
|
+
if (type === 'lower_case') return text.toLowerCase();
|
|
3134
|
+
if (type === 'title_case') return text.toLowerCase().replace(/\b\w/g, s => s.toUpperCase());
|
|
3135
|
+
return text;
|
|
3136
|
+
};
|
|
3137
|
+
|
|
3138
|
+
const transformTextStyle = (core, type) => {
|
|
3139
|
+
const range = core.state.range;
|
|
3140
|
+
if (!range) return;
|
|
3141
|
+
const startContainer = range.startContainer;
|
|
3142
|
+
const startOffset = range.startOffset;
|
|
3143
|
+
const endContainer = range.endContainer;
|
|
3144
|
+
let endOffset = range.endOffset;
|
|
3145
|
+
|
|
3146
|
+
const processTextNode = (node, start, end) => {
|
|
3147
|
+
const text = node.nodeValue;
|
|
3148
|
+
const transformedText = transformCase(text.slice(start, end), type);
|
|
3149
|
+
node.nodeValue = text.slice(0, start) + transformedText + text.slice(end);
|
|
3150
|
+
if (node === endContainer) endOffset = start + transformedText.length;
|
|
3151
|
+
};
|
|
3152
|
+
|
|
3153
|
+
if (range.commonAncestorContainer.nodeType === Node.TEXT_NODE) {
|
|
3154
|
+
processTextNode(range.commonAncestorContainer, range.startOffset, range.endOffset);
|
|
3155
|
+
} else {
|
|
3156
|
+
const iterator = core.elements.iframeWindow.createNodeIterator(
|
|
3157
|
+
range.commonAncestorContainer,
|
|
3158
|
+
NodeFilter.SHOW_TEXT,
|
|
3159
|
+
{
|
|
3160
|
+
acceptNode: (node) => {
|
|
3161
|
+
return range.intersectsNode(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
);
|
|
3165
|
+
|
|
3166
|
+
const nodes = [];
|
|
3167
|
+
let node;
|
|
3168
|
+
while ((node = iterator.nextNode())) {
|
|
3169
|
+
nodes.push(node);
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
nodes.forEach(node => {
|
|
3173
|
+
let start = 0;
|
|
3174
|
+
let end = node.nodeValue.length;
|
|
3175
|
+
|
|
3176
|
+
if (node === range.startContainer) start = range.startOffset;
|
|
3177
|
+
if (node === range.endContainer) end = range.endOffset;
|
|
3178
|
+
|
|
3179
|
+
processTextNode(node, start, end);
|
|
3180
|
+
});
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3183
|
+
const newRange = core.elements.iframeWindow.createRange();
|
|
3184
|
+
newRange.setStart(startContainer, startOffset);
|
|
3185
|
+
newRange.setEnd(endContainer, endOffset);
|
|
3186
|
+
const selection = core.elements.iframeWindow.getSelection();
|
|
3187
|
+
selection.removeAllRanges();
|
|
3188
|
+
selection.addRange(newRange);
|
|
3189
|
+
}
|
|
3076
3190
|
export {
|
|
3077
3191
|
cleanHTML,
|
|
3078
3192
|
debounce,
|
|
@@ -3114,4 +3228,6 @@ export {
|
|
|
3114
3228
|
makeStrikethrough,
|
|
3115
3229
|
makeCodeBlock,
|
|
3116
3230
|
makeSublist,
|
|
3231
|
+
transformTextStyle,
|
|
3232
|
+
makeToolbarButtonSelect,
|
|
3117
3233
|
}
|