@8btc/mditor 0.0.7 → 0.0.9
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/index.css +56 -2
- package/dist/index.d.ts +9 -0
- package/dist/index.js +3289 -2841
- package/dist/index.min.js +1 -1
- package/dist/method.d.ts +14 -10
- package/dist/method.js +527 -3
- package/dist/method.min.js +1 -1
- package/dist/ts/util/editorCommonEvent.d.ts +3 -2
- package/dist/ts/wysiwyg/index.d.ts +29 -0
- package/dist/types/index.d.ts +18 -2
- package/package.json +1 -1
- package/src/assets/less/_line-number.less +6 -1
- package/src/assets/less/_selection-popover.less +148 -0
- package/src/assets/less/_selection-tag.less +38 -0
- package/src/assets/less/index.less +2 -0
- package/src/index.ts +58 -3
- package/src/method.ts +1 -1
- package/src/ts/ir/index.ts +1 -1
- package/src/ts/ir/process.ts +1 -1
- package/src/ts/markdown/selectionRender.ts +28 -0
- package/src/ts/preview/index.ts +6 -5
- package/src/ts/sv/index.ts +1 -1
- package/src/ts/sv/process.ts +1 -1
- package/src/ts/ui/initUI.ts +4 -2
- package/src/ts/util/Options.ts +8 -1
- package/src/ts/util/editorCommonEvent.ts +296 -184
- package/src/ts/util/processCode.ts +43 -24
- package/src/ts/wysiwyg/afterRenderEvent.ts +1 -1
- package/src/ts/wysiwyg/index.ts +509 -119
- package/src/ts/wysiwyg/renderDomByMd.ts +1 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import {Constants} from "../constants";
|
|
2
|
-
import {processHeading} from "../ir/process";
|
|
3
|
-
import {processKeydown as irProcessKeydown} from "../ir/processKeydown";
|
|
4
|
-
import {getMarkdown} from "../markdown/getMarkdown";
|
|
5
|
-
import {previewImage} from "../preview/image";
|
|
6
|
-
import {processHeading as processHeadingSV} from "../sv/process";
|
|
7
|
-
import {processKeydown as mdProcessKeydown} from "../sv/processKeydown";
|
|
8
|
-
import {setEditMode} from "../toolbar/EditMode";
|
|
9
|
-
import {hidePanel} from "../toolbar/setToolbar";
|
|
10
|
-
import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
|
|
11
|
-
import {processKeydown} from "../wysiwyg/processKeydown";
|
|
12
|
-
import {removeHeading, setHeading} from "../wysiwyg/setHeading";
|
|
13
|
-
import {getEventName, isCtrl} from "./compatibility";
|
|
14
|
-
import {execAfterRender, paste} from "./fixBrowserBehavior";
|
|
15
|
-
import {getSelectText} from "./getSelectText";
|
|
16
|
-
import {hasClosestByAttribute, hasClosestByMatchTag} from "./hasClosest";
|
|
17
|
-
import {matchHotKey} from "./hotKey";
|
|
18
|
-
import {getCursorPosition, getEditorRange} from "./selection";
|
|
1
|
+
import { Constants } from "../constants";
|
|
2
|
+
import { processHeading } from "../ir/process";
|
|
3
|
+
import { processKeydown as irProcessKeydown } from "../ir/processKeydown";
|
|
4
|
+
import { getMarkdown } from "../markdown/getMarkdown";
|
|
5
|
+
import { previewImage } from "../preview/image";
|
|
6
|
+
import { processHeading as processHeadingSV } from "../sv/process";
|
|
7
|
+
import { processKeydown as mdProcessKeydown } from "../sv/processKeydown";
|
|
8
|
+
import { setEditMode } from "../toolbar/EditMode";
|
|
9
|
+
import { hidePanel } from "../toolbar/setToolbar";
|
|
10
|
+
import { afterRenderEvent } from "../wysiwyg/afterRenderEvent";
|
|
11
|
+
import { processKeydown } from "../wysiwyg/processKeydown";
|
|
12
|
+
import { removeHeading, setHeading } from "../wysiwyg/setHeading";
|
|
13
|
+
import { getEventName, isCtrl } from "./compatibility";
|
|
14
|
+
import { execAfterRender, paste } from "./fixBrowserBehavior";
|
|
15
|
+
import { getSelectText } from "./getSelectText";
|
|
16
|
+
import { hasClosestByAttribute, hasClosestByMatchTag } from "./hasClosest";
|
|
17
|
+
import { matchHotKey } from "./hotKey";
|
|
18
|
+
import { getCursorPosition, getEditorRange } from "./selection";
|
|
19
19
|
|
|
20
20
|
export const focusEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
21
21
|
editorElement.addEventListener("focus", () => {
|
|
@@ -27,27 +27,40 @@ export const focusEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
export const dblclickEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
30
|
-
editorElement.addEventListener(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
editorElement.addEventListener(
|
|
31
|
+
"dblclick",
|
|
32
|
+
(event: MouseEvent & { target: HTMLElement }) => {
|
|
33
|
+
if (event.target.tagName === "IMG") {
|
|
34
|
+
if (vditor.options.image.preview) {
|
|
35
|
+
vditor.options.image.preview(event.target);
|
|
36
|
+
} else if (vditor.options.image.isPreview) {
|
|
37
|
+
previewImage(
|
|
38
|
+
event.target as HTMLImageElement,
|
|
39
|
+
vditor.options.lang,
|
|
40
|
+
vditor.options.theme
|
|
41
|
+
);
|
|
42
|
+
}
|
|
36
43
|
}
|
|
37
44
|
}
|
|
38
|
-
|
|
45
|
+
);
|
|
39
46
|
};
|
|
40
47
|
|
|
41
48
|
export const blurEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
42
49
|
editorElement.addEventListener("blur", (event) => {
|
|
43
50
|
if (vditor.currentMode === "ir") {
|
|
44
|
-
const expandElement = vditor.ir.element.querySelector(
|
|
51
|
+
const expandElement = vditor.ir.element.querySelector(
|
|
52
|
+
".vditor-ir__node--expand"
|
|
53
|
+
);
|
|
45
54
|
if (expandElement) {
|
|
46
55
|
expandElement.classList.remove("vditor-ir__node--expand");
|
|
47
56
|
}
|
|
48
|
-
} else if (
|
|
49
|
-
|
|
50
|
-
vditor.wysiwyg.
|
|
57
|
+
} else if (
|
|
58
|
+
vditor.currentMode === "wysiwyg" &&
|
|
59
|
+
!vditor.wysiwyg.selectPopover.contains(
|
|
60
|
+
event.relatedTarget as HTMLElement
|
|
61
|
+
)
|
|
62
|
+
) {
|
|
63
|
+
vditor.wysiwyg.hideSelectionPopover();
|
|
51
64
|
}
|
|
52
65
|
vditor[vditor.currentMode].range = getEditorRange(vditor);
|
|
53
66
|
if (vditor.options.blur) {
|
|
@@ -59,14 +72,26 @@ export const blurEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
|
59
72
|
export const dropEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
60
73
|
editorElement.addEventListener("dragstart", (event) => {
|
|
61
74
|
// 选中编辑器中的文字进行拖拽
|
|
62
|
-
event.dataTransfer.setData(
|
|
75
|
+
event.dataTransfer.setData(
|
|
76
|
+
Constants.DROP_EDITOR,
|
|
77
|
+
Constants.DROP_EDITOR
|
|
78
|
+
);
|
|
63
79
|
});
|
|
64
|
-
editorElement.addEventListener(
|
|
65
|
-
|
|
80
|
+
editorElement.addEventListener(
|
|
81
|
+
"drop",
|
|
82
|
+
(
|
|
83
|
+
event: ClipboardEvent & {
|
|
84
|
+
dataTransfer?: DataTransfer;
|
|
85
|
+
target: HTMLElement;
|
|
86
|
+
}
|
|
87
|
+
) => {
|
|
66
88
|
if (event.dataTransfer.getData(Constants.DROP_EDITOR)) {
|
|
67
89
|
// 编辑器内选中文字拖拽
|
|
68
90
|
execAfterRender(vditor);
|
|
69
|
-
} else if (
|
|
91
|
+
} else if (
|
|
92
|
+
event.dataTransfer.types.includes("Files") ||
|
|
93
|
+
event.dataTransfer.types.includes("text/html")
|
|
94
|
+
) {
|
|
70
95
|
// 外部文件拖入编辑器中或者编辑器内选中文字拖拽
|
|
71
96
|
paste(vditor, event, {
|
|
72
97
|
pasteCode: (code: string) => {
|
|
@@ -74,197 +99,284 @@ export const dropEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
|
74
99
|
},
|
|
75
100
|
});
|
|
76
101
|
}
|
|
77
|
-
}
|
|
102
|
+
}
|
|
103
|
+
);
|
|
78
104
|
};
|
|
79
105
|
|
|
80
|
-
export const copyEvent =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
106
|
+
export const copyEvent = (
|
|
107
|
+
vditor: IVditor,
|
|
108
|
+
editorElement: HTMLElement,
|
|
109
|
+
copy: (event: ClipboardEvent, vditor: IVditor) => void
|
|
110
|
+
) => {
|
|
111
|
+
editorElement.addEventListener("copy", (event: ClipboardEvent) =>
|
|
112
|
+
copy(event, vditor)
|
|
113
|
+
);
|
|
114
|
+
};
|
|
84
115
|
|
|
85
|
-
export const cutEvent =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
116
|
+
export const cutEvent = (
|
|
117
|
+
vditor: IVditor,
|
|
118
|
+
editorElement: HTMLElement,
|
|
119
|
+
copy: (event: ClipboardEvent, vditor: IVditor) => void
|
|
120
|
+
) => {
|
|
121
|
+
editorElement.addEventListener("cut", (event: ClipboardEvent) => {
|
|
122
|
+
copy(event, vditor);
|
|
123
|
+
// 获取 comment
|
|
124
|
+
if (vditor.options.comment.enable && vditor.currentMode === "wysiwyg") {
|
|
125
|
+
vditor.wysiwyg.getComments(vditor);
|
|
126
|
+
}
|
|
127
|
+
document.execCommand("delete");
|
|
128
|
+
});
|
|
129
|
+
};
|
|
96
130
|
|
|
97
131
|
export const scrollCenter = (vditor: IVditor) => {
|
|
98
132
|
if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable) {
|
|
99
|
-
vditor.options.comment.adjustTop(
|
|
133
|
+
vditor.options.comment.adjustTop(
|
|
134
|
+
vditor.wysiwyg.getComments(vditor, true)
|
|
135
|
+
);
|
|
100
136
|
}
|
|
101
137
|
if (!vditor.options.typewriterMode) {
|
|
102
138
|
return;
|
|
103
139
|
}
|
|
104
140
|
const editorElement = vditor[vditor.currentMode].element;
|
|
105
141
|
const cursorTop = getCursorPosition(editorElement).top;
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
142
|
+
if (
|
|
143
|
+
vditor.options.height === "auto" &&
|
|
144
|
+
!vditor.element.classList.contains("vditor--fullscreen")
|
|
145
|
+
) {
|
|
146
|
+
window.scrollTo(
|
|
147
|
+
window.scrollX,
|
|
148
|
+
cursorTop +
|
|
149
|
+
vditor.element.offsetTop +
|
|
150
|
+
vditor.toolbar.element.offsetHeight -
|
|
151
|
+
window.innerHeight / 2 +
|
|
152
|
+
10
|
|
153
|
+
);
|
|
109
154
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
155
|
+
if (
|
|
156
|
+
vditor.options.height !== "auto" ||
|
|
157
|
+
vditor.element.classList.contains("vditor--fullscreen")
|
|
158
|
+
) {
|
|
159
|
+
editorElement.scrollTop =
|
|
160
|
+
cursorTop +
|
|
161
|
+
editorElement.scrollTop -
|
|
162
|
+
editorElement.clientHeight / 2 +
|
|
163
|
+
10;
|
|
112
164
|
}
|
|
113
165
|
};
|
|
114
166
|
|
|
115
167
|
export const hotkeyEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
116
|
-
editorElement.addEventListener(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if ((vditor.options.hint.extend.length > 1 || vditor.toolbar.elements.emoji) &&
|
|
122
|
-
vditor.hint.select(event, vditor)) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 重置 comment
|
|
127
|
-
if (vditor.options.comment.enable && vditor.currentMode === "wysiwyg" &&
|
|
128
|
-
(event.key === "Backspace" || matchHotKey("⌘X", event))) {
|
|
129
|
-
vditor.wysiwyg.getComments(vditor);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (vditor.currentMode === "sv") {
|
|
133
|
-
if (mdProcessKeydown(vditor, event)) {
|
|
134
|
-
return;
|
|
168
|
+
editorElement.addEventListener(
|
|
169
|
+
"keydown",
|
|
170
|
+
(event: KeyboardEvent & { target: HTMLElement }) => {
|
|
171
|
+
if (!event.isComposing && vditor.options.keydown) {
|
|
172
|
+
vditor.options.keydown(event);
|
|
135
173
|
}
|
|
136
|
-
|
|
137
|
-
if (
|
|
174
|
+
// hint: 上下选择
|
|
175
|
+
if (
|
|
176
|
+
(vditor.options.hint.extend.length > 1 ||
|
|
177
|
+
vditor.toolbar.elements.emoji) &&
|
|
178
|
+
vditor.hint.select(event, vditor)
|
|
179
|
+
) {
|
|
138
180
|
return;
|
|
139
181
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
182
|
+
|
|
183
|
+
// 重置 comment
|
|
184
|
+
if (
|
|
185
|
+
vditor.options.comment.enable &&
|
|
186
|
+
vditor.currentMode === "wysiwyg" &&
|
|
187
|
+
(event.key === "Backspace" || matchHotKey("⌘X", event))
|
|
188
|
+
) {
|
|
189
|
+
vditor.wysiwyg.getComments(vditor);
|
|
143
190
|
}
|
|
144
|
-
}
|
|
145
191
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
192
|
+
if (vditor.currentMode === "sv") {
|
|
193
|
+
if (mdProcessKeydown(vditor, event)) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
} else if (vditor.currentMode === "wysiwyg") {
|
|
197
|
+
if (processKeydown(vditor, event)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
} else if (vditor.currentMode === "ir") {
|
|
201
|
+
if (irProcessKeydown(vditor, event)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
151
205
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
206
|
+
if (vditor.options.ctrlEnter && matchHotKey("⌘Enter", event)) {
|
|
207
|
+
vditor.options.ctrlEnter(getMarkdown(vditor));
|
|
208
|
+
event.preventDefault();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
158
211
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
212
|
+
// undo
|
|
213
|
+
if (matchHotKey("⌘Z", event) && !vditor.toolbar.elements.undo) {
|
|
214
|
+
vditor.undo.undo(vditor);
|
|
215
|
+
event.preventDefault();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
165
218
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
vditor.options.esc(getMarkdown(vditor));
|
|
219
|
+
// redo
|
|
220
|
+
if (matchHotKey("⌘Y", event) && !vditor.toolbar.elements.redo) {
|
|
221
|
+
vditor.undo.redo(vditor);
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
return;
|
|
172
224
|
}
|
|
173
|
-
event.preventDefault();
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
225
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
} else {
|
|
184
|
-
setHeading(vditor, tagName);
|
|
226
|
+
// esc
|
|
227
|
+
if (event.key === "Escape") {
|
|
228
|
+
if (vditor.hint.element.style.display === "block") {
|
|
229
|
+
vditor.hint.element.style.display = "none";
|
|
230
|
+
} else if (vditor.options.esc && !event.isComposing) {
|
|
231
|
+
vditor.options.esc(getMarkdown(vditor));
|
|
185
232
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
processHeadingSV(vditor, "#".repeat(parseInt(event.code.replace("Digit", ""), 10)) + " ");
|
|
189
|
-
} else if (vditor.currentMode === "ir") {
|
|
190
|
-
processHeading(vditor, "#".repeat(parseInt(event.code.replace("Digit", ""), 10)) + " ");
|
|
233
|
+
event.preventDefault();
|
|
234
|
+
return;
|
|
191
235
|
}
|
|
192
|
-
event.preventDefault();
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
236
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
237
|
+
// h1 - h6 hotkey
|
|
238
|
+
if (
|
|
239
|
+
isCtrl(event) &&
|
|
240
|
+
event.altKey &&
|
|
241
|
+
!event.shiftKey &&
|
|
242
|
+
/^Digit[1-6]$/.test(event.code)
|
|
243
|
+
) {
|
|
244
|
+
if (vditor.currentMode === "wysiwyg") {
|
|
245
|
+
const tagName = event.code.replace("Digit", "H");
|
|
246
|
+
if (
|
|
247
|
+
hasClosestByMatchTag(
|
|
248
|
+
getSelection().getRangeAt(0).startContainer,
|
|
249
|
+
tagName
|
|
250
|
+
)
|
|
251
|
+
) {
|
|
252
|
+
removeHeading(vditor);
|
|
253
|
+
} else {
|
|
254
|
+
setHeading(vditor, tagName);
|
|
255
|
+
}
|
|
256
|
+
afterRenderEvent(vditor);
|
|
257
|
+
} else if (vditor.currentMode === "sv") {
|
|
258
|
+
processHeadingSV(
|
|
259
|
+
vditor,
|
|
260
|
+
"#".repeat(
|
|
261
|
+
parseInt(event.code.replace("Digit", ""), 10)
|
|
262
|
+
) + " "
|
|
263
|
+
);
|
|
264
|
+
} else if (vditor.currentMode === "ir") {
|
|
265
|
+
processHeading(
|
|
266
|
+
vditor,
|
|
267
|
+
"#".repeat(
|
|
268
|
+
parseInt(event.code.replace("Digit", ""), 10)
|
|
269
|
+
) + " "
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
return true;
|
|
204
274
|
}
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
275
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
return sub ? true : false;
|
|
276
|
+
// toggle edit mode
|
|
277
|
+
if (
|
|
278
|
+
isCtrl(event) &&
|
|
279
|
+
event.altKey &&
|
|
280
|
+
!event.shiftKey &&
|
|
281
|
+
/^Digit[7-9]$/.test(event.code)
|
|
282
|
+
) {
|
|
283
|
+
if (event.code === "Digit7") {
|
|
284
|
+
setEditMode(vditor, "wysiwyg", event);
|
|
285
|
+
} else if (event.code === "Digit8") {
|
|
286
|
+
setEditMode(vditor, "ir", event);
|
|
287
|
+
} else if (event.code === "Digit9") {
|
|
288
|
+
setEditMode(vditor, "sv", event);
|
|
224
289
|
}
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
if (matchHotKey(menuItem.hotkey, event)) {
|
|
228
|
-
vditor.toolbar.elements[menuItem.name].children[0].dispatchEvent(new CustomEvent(getEventName()));
|
|
229
|
-
event.preventDefault();
|
|
230
290
|
return true;
|
|
231
291
|
}
|
|
232
|
-
|
|
233
|
-
|
|
292
|
+
|
|
293
|
+
// toolbar action
|
|
294
|
+
vditor.options.toolbar.find((menuItem: IMenuItem) => {
|
|
295
|
+
if (!menuItem.hotkey || menuItem.toolbar) {
|
|
296
|
+
if (menuItem.toolbar) {
|
|
297
|
+
const sub = menuItem.toolbar.find(
|
|
298
|
+
(subMenuItem: IMenuItem) => {
|
|
299
|
+
if (!subMenuItem.hotkey) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
if (matchHotKey(subMenuItem.hotkey, event)) {
|
|
303
|
+
vditor.toolbar.elements[
|
|
304
|
+
subMenuItem.name
|
|
305
|
+
].children[0].dispatchEvent(
|
|
306
|
+
new CustomEvent(getEventName())
|
|
307
|
+
);
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
return sub ? true : false;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
if (matchHotKey(menuItem.hotkey, event)) {
|
|
318
|
+
vditor.toolbar.elements[
|
|
319
|
+
menuItem.name
|
|
320
|
+
].children[0].dispatchEvent(
|
|
321
|
+
new CustomEvent(getEventName())
|
|
322
|
+
);
|
|
323
|
+
event.preventDefault();
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
);
|
|
234
329
|
};
|
|
235
330
|
|
|
236
331
|
/**
|
|
237
|
-
*
|
|
238
|
-
* -
|
|
332
|
+
* 选区事件处理(含防抖):根据选中内容显示/隐藏选择浮窗
|
|
333
|
+
* - 受 options.selectionPopover.enable 控制
|
|
334
|
+
* - 防抖间隔使用 options.selectionPopover.debounceDelay(默认 150ms)
|
|
239
335
|
*/
|
|
240
336
|
export const selectEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (vditor.options.select) {
|
|
257
|
-
vditor.options.select(selectText);
|
|
258
|
-
}
|
|
259
|
-
} else {
|
|
260
|
-
if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable) {
|
|
261
|
-
vditor.wysiwyg.hideComment();
|
|
262
|
-
}
|
|
263
|
-
if (typeof vditor.options.unSelect === 'function') {
|
|
264
|
-
vditor.options.unSelect();
|
|
265
|
-
}
|
|
337
|
+
let debounceTimer = 0;
|
|
338
|
+
const handleSelection = () => {
|
|
339
|
+
window.clearTimeout(debounceTimer);
|
|
340
|
+
const delay =
|
|
341
|
+
vditor.options.selectionPopover?.debounceDelay ?? 150;
|
|
342
|
+
debounceTimer = window.setTimeout(() => {
|
|
343
|
+
const selectText = getSelectText(
|
|
344
|
+
vditor[vditor.currentMode].element
|
|
345
|
+
);
|
|
346
|
+
if (selectText.trim()) {
|
|
347
|
+
if (
|
|
348
|
+
vditor.currentMode === "wysiwyg" &&
|
|
349
|
+
vditor.options.selectionPopover?.enable
|
|
350
|
+
) {
|
|
351
|
+
vditor.wysiwyg.showSelectionPopover();
|
|
266
352
|
}
|
|
267
|
-
|
|
268
|
-
|
|
353
|
+
if (vditor.options.select) {
|
|
354
|
+
vditor.options.select(selectText);
|
|
355
|
+
}
|
|
356
|
+
} else {
|
|
357
|
+
if (vditor.currentMode === "wysiwyg") {
|
|
358
|
+
vditor.wysiwyg.hideSelectionPopover();
|
|
359
|
+
}
|
|
360
|
+
if (typeof vditor.options.unSelect === "function") {
|
|
361
|
+
vditor.options.unSelect();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}, delay);
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
editorElement.addEventListener(
|
|
368
|
+
"selectstart",
|
|
369
|
+
(event: Event & { target: HTMLElement }) => {
|
|
370
|
+
editorElement.onmouseup = handleSelection;
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
editorElement.addEventListener("keyup", (event: KeyboardEvent) => {
|
|
375
|
+
if (event.shiftKey && (event.key.startsWith("Arrow") || event.key === "Home" || event.key === "End")) {
|
|
376
|
+
handleSelection();
|
|
377
|
+
} else if (!event.shiftKey && (event.key.startsWith("Arrow") || event.key === "Escape")) {
|
|
378
|
+
// Cancel selection or move cursor without selection
|
|
379
|
+
handleSelection();
|
|
380
|
+
}
|
|
269
381
|
});
|
|
270
382
|
};
|
|
@@ -24,30 +24,30 @@ export const processPasteCode = (html: string, text: string, type = "sv") => {
|
|
|
24
24
|
// 适配单独粘贴公式,使用 $$ 包装
|
|
25
25
|
const formulaRegex = new RegExp(
|
|
26
26
|
"^(?:" +
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
27
|
+
[
|
|
28
|
+
// 原有:基础数学命令(求和、分式、三角函数等)
|
|
29
|
+
/\\(sum|prod|frac|int|sqrt|lim|log|sin|cos|tan|displaystyle|textstyle|mathbb|mathbf|overline|underline|vec|hat|bar|cdot|leq|geq|neq|approx|to|xrightarrow|rightarrow|leftarrow|infty|partial|nabla)/
|
|
30
|
+
.source,
|
|
31
|
+
// 原有:公式环境(如\begin{align}、\begin{equation}等)
|
|
32
|
+
/\\begin\{[^}]+\}/.source,
|
|
33
|
+
// 原有:左右括号命令(如\left(、\right]等)
|
|
34
|
+
/\\left|\\right/.source,
|
|
35
|
+
// 原有:化学/物理单位命令(如\ce{、\pu{)
|
|
36
|
+
/\\(ce|pu)\{/.source,
|
|
37
|
+
// 新增:希腊字母命令(如\alpha、\beta、\Gamma等)
|
|
38
|
+
/\\[a-zA-Z]+\b(?!\d)/.source,
|
|
39
|
+
// 新增:带数字/符号的命令(如\H_2、\text{...}、\mathbf{...}等)
|
|
40
|
+
/\\[a-zA-Z]+\d*\{/.source,
|
|
41
|
+
// 新增:特殊符号命令(如\$、\%、\&等)
|
|
42
|
+
/\\[^\w]/.source,
|
|
43
|
+
// 新增:上下标相关命令(如\underset、\overset)
|
|
44
|
+
/\\(underset|overset|substack|boxed|bbox)/.source,
|
|
45
|
+
// 新增:矩阵/数组环境起始(如\begin{matrix})
|
|
46
|
+
/\\begin\{(matrix|array|pmatrix|bmatrix|vmatrix)\}/.source,
|
|
47
|
+
// 新增:其他数学函数(如 \operatorname)
|
|
48
|
+
/\\operatorname/.source,
|
|
49
|
+
].join("|") +
|
|
50
|
+
")"
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
if (formulaRegex.test(trimmedText)) {
|
|
@@ -197,6 +197,25 @@ export const processCodeRender = (
|
|
|
197
197
|
cdn: vditor.options.cdn,
|
|
198
198
|
math: vditor.options.preview.math,
|
|
199
199
|
});
|
|
200
|
+
} else if (language === "selection") {
|
|
201
|
+
// 渲染文件选择标签
|
|
202
|
+
const content = previewPanel.textContent.trim();
|
|
203
|
+
const lines = content.split('\n');
|
|
204
|
+
const tags = lines.map(line => {
|
|
205
|
+
const match = line.trim().match(/^(.+?)\s+(\d+-\d+)$/);
|
|
206
|
+
if (match) {
|
|
207
|
+
const [, filename, lineRange] = match;
|
|
208
|
+
return `<div class="vditor-selection-tag">
|
|
209
|
+
<span class="vditor-selection-tag__file">${filename}</span>
|
|
210
|
+
<span class="vditor-selection-tag__lines">${lineRange}</span>
|
|
211
|
+
</div>`;
|
|
212
|
+
}
|
|
213
|
+
return '';
|
|
214
|
+
}).filter(tag => tag).join('');
|
|
215
|
+
|
|
216
|
+
if (tags) {
|
|
217
|
+
previewPanel.innerHTML = tags;
|
|
218
|
+
}
|
|
200
219
|
} else {
|
|
201
220
|
const cRender = vditor.options.customRenders.find((item) => {
|
|
202
221
|
if (item.language === language) {
|