@krainovsd/markdown-editor 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/index-CDtGUxs-.js +52 -0
- package/lib/cjs/index-CDtGUxs-.js.map +1 -0
- package/lib/cjs/{index-JTLnXX8Q.js → index-CiorogHq.js} +979 -372
- package/lib/cjs/index-CiorogHq.js.map +1 -0
- package/lib/cjs/index.js +6 -3
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/extensions/init-extensions.js +6 -2
- package/lib/esm/extensions/init-extensions.js.map +1 -1
- package/lib/esm/extensions/listeners/get-focus-event.js +1 -0
- package/lib/esm/extensions/listeners/get-focus-event.js.map +1 -1
- package/lib/esm/extensions/markdown/blockquote/blockquote-decoration.js +2 -2
- package/lib/esm/extensions/markdown/blockquote/blockquote-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/bold/bold-decoration.js +2 -2
- package/lib/esm/extensions/markdown/bold/bold-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/code/code-decoration.js +2 -2
- package/lib/esm/extensions/markdown/code/code-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/header/header-decoration.js +3 -3
- package/lib/esm/extensions/markdown/header/header-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/horizontal/horizontal-decoration.js +2 -2
- package/lib/esm/extensions/markdown/horizontal/horizontal-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/image/image-decoration.js +33 -26
- package/lib/esm/extensions/markdown/image/image-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/image/image-widget.js +82 -74
- package/lib/esm/extensions/markdown/image/image-widget.js.map +1 -1
- package/lib/esm/extensions/markdown/init-markdown.js +5 -2
- package/lib/esm/extensions/markdown/init-markdown.js.map +1 -1
- package/lib/esm/extensions/markdown/italic/italic-decoration.js +7 -7
- package/lib/esm/extensions/markdown/italic/italic-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/link/auto-link-decoration.js +24 -4
- package/lib/esm/extensions/markdown/link/auto-link-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/link/link-decoration.js +25 -5
- package/lib/esm/extensions/markdown/link/link-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/link/link-label-decoration.js +3 -2
- package/lib/esm/extensions/markdown/link/link-label-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/link/link-widget.js +137 -112
- package/lib/esm/extensions/markdown/link/link-widget.js.map +1 -1
- package/lib/esm/extensions/markdown/list/list-decoration.js +3 -3
- package/lib/esm/extensions/markdown/list/list-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/markdown-decoration.js +89 -44
- package/lib/esm/extensions/markdown/markdown-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/markdown-state.js +29 -0
- package/lib/esm/extensions/markdown/markdown-state.js.map +1 -0
- package/lib/esm/extensions/markdown/mention/mention-decoration.js +2 -2
- package/lib/esm/extensions/markdown/mention/mention-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/strike-through/strike-through-decoration.js +2 -2
- package/lib/esm/extensions/markdown/strike-through/strike-through-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/todo/todo-decoration.js +3 -3
- package/lib/esm/extensions/markdown/todo/todo-decoration.js.map +1 -1
- package/lib/esm/extensions/markdown/todo/todo-widget.js +1 -0
- package/lib/esm/extensions/markdown/todo/todo-widget.js.map +1 -1
- package/lib/esm/extensions/settings/init-settings.js +1 -0
- package/lib/esm/extensions/settings/init-settings.js.map +1 -1
- package/lib/esm/index.js +9 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/lib/utils/get-decoration.js +2 -1
- package/lib/esm/lib/utils/get-decoration.js.map +1 -1
- package/lib/esm/module/Editor/Editor.js +4 -0
- package/lib/esm/module/Editor/Editor.js.map +1 -1
- package/lib/esm/module/Editor/lib/init-editor.js +1 -0
- package/lib/esm/module/Editor/lib/init-editor.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/package.json +1 -1
- package/lib/cjs/index-JTLnXX8Q.js.map +0 -1
- package/lib/cjs/index-v4GhIAcy.js +0 -528
- package/lib/cjs/index-v4GhIAcy.js.map +0 -1
- package/lib/esm/lib/utils/tick.js +0 -22
- package/lib/esm/lib/utils/tick.js.map +0 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
|
-
|
|
5
|
-
const langMarkdown = require('@codemirror/lang-markdown');
|
|
6
|
-
const language = require('@codemirror/language');
|
|
7
3
|
const view = require('@codemirror/view');
|
|
4
|
+
const state = require('@codemirror/state');
|
|
5
|
+
const commands = require('@codemirror/commands');
|
|
6
|
+
const language = require('@codemirror/language');
|
|
7
|
+
const highlight = require('@lezer/highlight');
|
|
8
|
+
require('@codemirror/lang-markdown');
|
|
8
9
|
const clsx = require('clsx');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
require('y-websocket');
|
|
11
|
+
|
|
12
|
+
const ReadonlyCompartment = new state.Compartment();
|
|
13
|
+
const VimModeCompartment = new state.Compartment();
|
|
14
|
+
const ThemeCompartment = new state.Compartment();
|
|
13
15
|
|
|
14
16
|
function copyToClipboard(content) {
|
|
15
17
|
if (navigator.clipboard && window.isSecureContext) {
|
|
@@ -44,34 +46,15 @@ function fallbackCopyTextToClipboard(content) {
|
|
|
44
46
|
});
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
function tick({ deep = 1, maxDeep = 1, delay = 0, recursiveCondition, delayGetter, type = "macro", }) {
|
|
48
|
-
return new Promise((resolve) => {
|
|
49
|
-
if (type === "micro") {
|
|
50
|
-
if (deep >= maxDeep || !recursiveCondition || recursiveCondition())
|
|
51
|
-
resolve(1);
|
|
52
|
-
else
|
|
53
|
-
void tick({ deep: deep + 1, maxDeep, delay, recursiveCondition, type, delayGetter }).then(() => resolve(1));
|
|
54
|
-
}
|
|
55
|
-
if (type === "macro") {
|
|
56
|
-
const currentDelay = delayGetter ? delayGetter(deep) : delay;
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
if (deep >= maxDeep || !recursiveCondition || recursiveCondition())
|
|
59
|
-
resolve(1);
|
|
60
|
-
else
|
|
61
|
-
void tick({ deep: deep + 1, maxDeep, delay, recursiveCondition, type, delayGetter }).then(() => resolve(1));
|
|
62
|
-
}, currentDelay);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
49
|
function getLineDecoration({ style, range }) {
|
|
68
50
|
return view.Decoration.line({
|
|
69
51
|
class: style,
|
|
70
52
|
}).range(range[0], range[1]);
|
|
71
53
|
}
|
|
72
|
-
function getMarkDecoration({ range, style }) {
|
|
54
|
+
function getMarkDecoration({ range, style, attributes }) {
|
|
73
55
|
return view.Decoration.mark({
|
|
74
56
|
class: style,
|
|
57
|
+
attributes,
|
|
75
58
|
}).range(range[0], range[1]);
|
|
76
59
|
}
|
|
77
60
|
function getHideDecoration({ range }) {
|
|
@@ -92,6 +75,312 @@ function isInRange(ranges, text) {
|
|
|
92
75
|
return ranges.some((range) => isRangeOverlap([range.from, range.to], text));
|
|
93
76
|
}
|
|
94
77
|
|
|
78
|
+
function saveDispatch(dispatch) {
|
|
79
|
+
queueMicrotask(() => {
|
|
80
|
+
dispatch();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* t.processingInstruction, t.meta - # () []
|
|
86
|
+
* t.url, t.link - links
|
|
87
|
+
*/
|
|
88
|
+
function getHighlightTemplate(config) {
|
|
89
|
+
return language.syntaxHighlighting(language.HighlightStyle.define([
|
|
90
|
+
{ tag: highlight.tags.keyword, color: config.keyword },
|
|
91
|
+
{ tag: [highlight.tags.name, highlight.tags.deleted, highlight.tags.character, highlight.tags.macroName], color: config.variable },
|
|
92
|
+
{ tag: [highlight.tags.propertyName], color: config.function },
|
|
93
|
+
{
|
|
94
|
+
tag: [highlight.tags.string, highlight.tags.inserted, highlight.tags.special(highlight.tags.string)],
|
|
95
|
+
color: config.string,
|
|
96
|
+
},
|
|
97
|
+
{ tag: [highlight.tags.function(highlight.tags.variableName), highlight.tags.labelName], color: config.function },
|
|
98
|
+
{ tag: [highlight.tags.color, highlight.tags.constant(highlight.tags.name), highlight.tags.standard(highlight.tags.name)], color: config.constant },
|
|
99
|
+
{ tag: [highlight.tags.definition(highlight.tags.name), highlight.tags.separator], color: config.variable },
|
|
100
|
+
{ tag: [highlight.tags.className], color: config.class },
|
|
101
|
+
{
|
|
102
|
+
tag: [highlight.tags.number, highlight.tags.changed, highlight.tags.annotation, highlight.tags.modifier, highlight.tags.self, highlight.tags.namespace],
|
|
103
|
+
color: config.number,
|
|
104
|
+
},
|
|
105
|
+
{ tag: [highlight.tags.typeName], color: config.type, fontStyle: config.type },
|
|
106
|
+
{ tag: [highlight.tags.operator, highlight.tags.operatorKeyword], color: config.keyword },
|
|
107
|
+
{ tag: [highlight.tags.escape, highlight.tags.regexp], color: config.regexp },
|
|
108
|
+
{ tag: [highlight.tags.comment], color: config.comment },
|
|
109
|
+
{ tag: [highlight.tags.atom, highlight.tags.bool, highlight.tags.special(highlight.tags.variableName)], color: config.variable },
|
|
110
|
+
{ tag: highlight.tags.invalid, color: config.invalid },
|
|
111
|
+
]));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const CLASSES = {
|
|
115
|
+
listCommon: "cm-list-common",
|
|
116
|
+
code: "cm-code",
|
|
117
|
+
codeButton: "cm-code-button",
|
|
118
|
+
codeButtonSuccess: "cm-code-button-success",
|
|
119
|
+
codeButtonFail: "cm-code-button-fail",
|
|
120
|
+
codeButtonPending: "cm-code-button-pending",
|
|
121
|
+
codeButtonSpan: "cm-code-span",
|
|
122
|
+
horizontal: "cm-horizontal",
|
|
123
|
+
blockquote: "cm-blockquote",
|
|
124
|
+
blockquoteInner: "cm-blockquote-inner",
|
|
125
|
+
link: "cm-link",
|
|
126
|
+
mention: "cm-mention",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
function getThemeTemplate(dark, config) {
|
|
130
|
+
return view.EditorView.theme({
|
|
131
|
+
"&": {
|
|
132
|
+
color: config.color,
|
|
133
|
+
backgroundColor: config.background,
|
|
134
|
+
},
|
|
135
|
+
".cm-content": {
|
|
136
|
+
fontFamily: config.fontFamily || "Montserrat",
|
|
137
|
+
},
|
|
138
|
+
"&.cm-focused > .cm-scroller > .cm-selectionLayer > .cm-selectionBackground": {
|
|
139
|
+
background: config.vimSelectionFocused,
|
|
140
|
+
},
|
|
141
|
+
"& .cm-selectionBackground": {
|
|
142
|
+
background: config.vimSelection,
|
|
143
|
+
},
|
|
144
|
+
"&.cm-editor.cm-focused": { outline: "none" },
|
|
145
|
+
"&.cm-editor": {
|
|
146
|
+
height: "100%",
|
|
147
|
+
width: "100%",
|
|
148
|
+
},
|
|
149
|
+
[`.${CLASSES.listCommon}:after`]: {
|
|
150
|
+
background: config.color,
|
|
151
|
+
},
|
|
152
|
+
[`.${CLASSES.code}`]: {
|
|
153
|
+
background: config.codeBackground,
|
|
154
|
+
color: config.codeColor,
|
|
155
|
+
},
|
|
156
|
+
[`.${CLASSES.horizontal}`]: {
|
|
157
|
+
borderBottomColor: config.horizontalColor,
|
|
158
|
+
},
|
|
159
|
+
[`.${CLASSES.link}`]: {
|
|
160
|
+
color: config.linkColor,
|
|
161
|
+
},
|
|
162
|
+
[`.${CLASSES.blockquote}`]: {
|
|
163
|
+
borderLeftColor: config.blockquoteColor,
|
|
164
|
+
},
|
|
165
|
+
[`.${CLASSES.blockquoteInner}:before`]: {
|
|
166
|
+
borderLeftColor: config.blockquoteColor,
|
|
167
|
+
},
|
|
168
|
+
[`.${CLASSES.codeButton}`]: {
|
|
169
|
+
color: config.codeButtonColor,
|
|
170
|
+
},
|
|
171
|
+
[`.${CLASSES.codeButton}:hover`]: {
|
|
172
|
+
background: config.codeButtonBackground,
|
|
173
|
+
},
|
|
174
|
+
[`.${CLASSES.codeButtonSuccess}:after`]: {
|
|
175
|
+
borderColor: config.codeButtonColor,
|
|
176
|
+
},
|
|
177
|
+
[`.${CLASSES.codeButtonFail}:after`]: {
|
|
178
|
+
background: config.codeButtonColor,
|
|
179
|
+
},
|
|
180
|
+
[`.${CLASSES.codeButtonFail}:before`]: {
|
|
181
|
+
background: config.codeButtonColor,
|
|
182
|
+
},
|
|
183
|
+
[`.${CLASSES.codeButtonPending}:before`]: {
|
|
184
|
+
borderColor: config.codeBackground,
|
|
185
|
+
borderTopColor: config.codeButtonColor,
|
|
186
|
+
},
|
|
187
|
+
[`.${CLASSES.mention}`]: {
|
|
188
|
+
color: config.mentionColor,
|
|
189
|
+
},
|
|
190
|
+
}, { dark });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const HIGHLIGHT_CONFIG$1 = {
|
|
194
|
+
keyword: "#f97583",
|
|
195
|
+
variable: "#ffab70",
|
|
196
|
+
function: "#79b8ff",
|
|
197
|
+
string: "#9ecbff",
|
|
198
|
+
constant: "#79b8ff",
|
|
199
|
+
type: "#79b8ff",
|
|
200
|
+
class: "#b392f0",
|
|
201
|
+
number: "#79b8ff",
|
|
202
|
+
comment: "#6a737d",
|
|
203
|
+
heading: "#79b8ff",
|
|
204
|
+
invalid: "#f97583",
|
|
205
|
+
regexp: "#9ecbff",
|
|
206
|
+
};
|
|
207
|
+
const THEME_CONFIG$1 = {
|
|
208
|
+
background: "#2E3235",
|
|
209
|
+
blockquoteColor: "#8A5CF5", // #6A8695
|
|
210
|
+
codeBackground: "#24292e",
|
|
211
|
+
codeButtonBackground: "#434C54FF",
|
|
212
|
+
codeButtonColor: "#DDDDDD",
|
|
213
|
+
codeColor: "#DDDDDD",
|
|
214
|
+
color: "#DDDDDD",
|
|
215
|
+
fontFamily: "Montserrat",
|
|
216
|
+
horizontalColor: "#DDDDDD",
|
|
217
|
+
linkColor: "#8A5CF5",
|
|
218
|
+
mentionColor: "#8A5CF5",
|
|
219
|
+
vimSelection: "#1A1919FF",
|
|
220
|
+
vimSelectionFocused: "#2E4B4BFF",
|
|
221
|
+
};
|
|
222
|
+
function getDarkTheme({ dark }) {
|
|
223
|
+
const highlightConfig = { ...HIGHLIGHT_CONFIG$1, ...(dark?.highlightConfig || {}) };
|
|
224
|
+
const themeConfig = { ...THEME_CONFIG$1, ...(dark?.themeConfig || {}) };
|
|
225
|
+
return [getThemeTemplate(true, themeConfig), getHighlightTemplate(highlightConfig)];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const HIGHLIGHT_CONFIG = {
|
|
229
|
+
keyword: "#9854f1",
|
|
230
|
+
variable: "#3760bf",
|
|
231
|
+
function: "#2e7de9",
|
|
232
|
+
string: "#587539",
|
|
233
|
+
constant: "#9854f1",
|
|
234
|
+
type: "#07879d",
|
|
235
|
+
class: "#3760bf",
|
|
236
|
+
number: "#b15c00",
|
|
237
|
+
comment: "#9da3c2",
|
|
238
|
+
heading: "#006a83",
|
|
239
|
+
invalid: "#ff3e64",
|
|
240
|
+
regexp: "#2e5857",
|
|
241
|
+
};
|
|
242
|
+
const THEME_CONFIG = {
|
|
243
|
+
background: "transparent",
|
|
244
|
+
blockquoteColor: "#8A5CF5", // #6A8695
|
|
245
|
+
codeBackground: "#e1e2e7",
|
|
246
|
+
codeButtonBackground: "#CCCCCDFF",
|
|
247
|
+
codeButtonColor: "#000000",
|
|
248
|
+
codeColor: "#000000",
|
|
249
|
+
color: "#000000",
|
|
250
|
+
fontFamily: "Montserrat",
|
|
251
|
+
horizontalColor: "#000000",
|
|
252
|
+
linkColor: "#8A5CF5",
|
|
253
|
+
mentionColor: "#8A5CF5",
|
|
254
|
+
vimSelection: "#d9d9d9",
|
|
255
|
+
vimSelectionFocused: "#d7d4f0",
|
|
256
|
+
};
|
|
257
|
+
function getLightTheme({ light }) {
|
|
258
|
+
const highlightConfig = { ...HIGHLIGHT_CONFIG, ...(light?.highlightConfig || {}) };
|
|
259
|
+
const themeConfig = { ...THEME_CONFIG, ...(light?.themeConfig || {}) };
|
|
260
|
+
return [getThemeTemplate(false, themeConfig), getHighlightTemplate(highlightConfig)];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const initTheme = (options) => {
|
|
264
|
+
const extensions = [
|
|
265
|
+
view.EditorView.lineWrapping,
|
|
266
|
+
ThemeCompartment.of(options.theme === "dark" ? getDarkTheme(options) : getLightTheme(options)),
|
|
267
|
+
];
|
|
268
|
+
return extensions;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
let vimMode = false;
|
|
272
|
+
let theme = "light";
|
|
273
|
+
const initKeyMaps = async ({ onEnter, onEscape, multiCursorMode, keyMaps, defaultKeyMaps, theme: initialTheme, vimMode: initialVimMode, dark, light, }) => {
|
|
274
|
+
vimMode = initialVimMode;
|
|
275
|
+
theme = initialTheme;
|
|
276
|
+
/** tab */
|
|
277
|
+
const keyBindings = [commands.indentWithTab];
|
|
278
|
+
/** standard */
|
|
279
|
+
keyBindings.push(...commands.standardKeymap.map((keyMap) => {
|
|
280
|
+
if (keyMap.key === "Enter" && onEnter) {
|
|
281
|
+
return {
|
|
282
|
+
key: "Enter",
|
|
283
|
+
shift: keyMap.run,
|
|
284
|
+
run: (view) => {
|
|
285
|
+
const response = onEnter(view);
|
|
286
|
+
if (response)
|
|
287
|
+
keyMap.run?.(view);
|
|
288
|
+
return response;
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return keyMap;
|
|
293
|
+
}));
|
|
294
|
+
/** vim */
|
|
295
|
+
if (defaultKeyMaps?.vim)
|
|
296
|
+
keyBindings.push({
|
|
297
|
+
key: "Mod-Alt-v",
|
|
298
|
+
run: (view$1) => {
|
|
299
|
+
vimMode = !vimMode;
|
|
300
|
+
void import('@replit/codemirror-vim').then(({ vim }) => {
|
|
301
|
+
saveDispatch(() => {
|
|
302
|
+
view$1.dispatch({
|
|
303
|
+
effects: VimModeCompartment.reconfigure(vimMode ? [vim({ status: true }), view.drawSelection()] : []),
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
return true;
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
/** theme */
|
|
311
|
+
if (defaultKeyMaps?.theme)
|
|
312
|
+
keyBindings.push({
|
|
313
|
+
key: "Mod-Alt-a",
|
|
314
|
+
run: (view) => {
|
|
315
|
+
theme = theme === "light" ? "dark" : "light";
|
|
316
|
+
saveDispatch(() => {
|
|
317
|
+
view.dispatch({
|
|
318
|
+
effects: ThemeCompartment.reconfigure(theme === "dark"
|
|
319
|
+
? getDarkTheme({
|
|
320
|
+
dark,
|
|
321
|
+
light,
|
|
322
|
+
theme,
|
|
323
|
+
})
|
|
324
|
+
: getLightTheme({
|
|
325
|
+
dark,
|
|
326
|
+
light,
|
|
327
|
+
theme,
|
|
328
|
+
})),
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
return true;
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
/** escape */
|
|
335
|
+
if (onEscape) {
|
|
336
|
+
keyBindings.push({
|
|
337
|
+
key: "Escape",
|
|
338
|
+
run: (view) => {
|
|
339
|
+
return onEscape(view);
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
/** custom */
|
|
344
|
+
if (keyMaps) {
|
|
345
|
+
keyBindings.push(...keyMaps);
|
|
346
|
+
}
|
|
347
|
+
/** history */
|
|
348
|
+
if (multiCursorMode) {
|
|
349
|
+
const { yUndoManagerKeymap } = await import('y-codemirror.next');
|
|
350
|
+
keyBindings.push(...yUndoManagerKeymap);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
keyBindings.push(...commands.historyKeymap);
|
|
354
|
+
}
|
|
355
|
+
return view.keymap.of(keyBindings);
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
function getChangeEvent({ onChange }) {
|
|
359
|
+
return onChange
|
|
360
|
+
? view.EditorView.updateListener.of((e) => {
|
|
361
|
+
if (e.docChanged) {
|
|
362
|
+
onChange(e);
|
|
363
|
+
}
|
|
364
|
+
})
|
|
365
|
+
: [];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function getFocusEvent({ onBlur, onFocus }) {
|
|
369
|
+
return onFocus || onBlur
|
|
370
|
+
? view.EditorView.focusChangeEffect.of((e, focus) => {
|
|
371
|
+
if (focus && onFocus)
|
|
372
|
+
onFocus(e);
|
|
373
|
+
else if (!focus && onBlur)
|
|
374
|
+
onBlur(e);
|
|
375
|
+
return null;
|
|
376
|
+
})
|
|
377
|
+
: [];
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function initListeners({ onBlur, onChange, onFocus }) {
|
|
381
|
+
return [getChangeEvent({ onChange }), getFocusEvent({ onBlur, onFocus })];
|
|
382
|
+
}
|
|
383
|
+
|
|
95
384
|
function styleInject(css, ref) {
|
|
96
385
|
if ( ref === void 0 ) ref = {};
|
|
97
386
|
var insertAt = ref.insertAt;
|
|
@@ -138,7 +427,7 @@ class BlockquoteWidget extends view.WidgetType {
|
|
|
138
427
|
span.classList.add(styles.blockquote__inner);
|
|
139
428
|
if (this.deep)
|
|
140
429
|
span.classList.add(styles["blockquote__inner-deep"]);
|
|
141
|
-
span.classList.add(
|
|
430
|
+
span.classList.add(CLASSES.blockquoteInner);
|
|
142
431
|
return span;
|
|
143
432
|
}
|
|
144
433
|
}
|
|
@@ -173,12 +462,12 @@ function getBlockquoteDecorations({ decorations, node, view }) {
|
|
|
173
462
|
}
|
|
174
463
|
if (!isInner) {
|
|
175
464
|
decorations.push(getLineDecoration({
|
|
176
|
-
style: clsx(styles.blockquote,
|
|
465
|
+
style: clsx(styles.blockquote, CLASSES.blockquote),
|
|
177
466
|
range: [line.from],
|
|
178
467
|
}));
|
|
179
468
|
}
|
|
180
469
|
}
|
|
181
|
-
function getBlockquoteSelectionDecorations({ decorations, node, view,
|
|
470
|
+
function getBlockquoteSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
182
471
|
if (node.name !== NAME_OF_BLOCKQUOTE_MARK) {
|
|
183
472
|
return;
|
|
184
473
|
}
|
|
@@ -211,7 +500,7 @@ function getBlockquoteSelectionDecorations({ decorations, node, view, isReadonly
|
|
|
211
500
|
pos = -1;
|
|
212
501
|
}
|
|
213
502
|
}
|
|
214
|
-
if (
|
|
503
|
+
if (forceActive ||
|
|
215
504
|
!view.hasFocus ||
|
|
216
505
|
!isInRange(view.state.selection.ranges, [line.from, line.to])) {
|
|
217
506
|
if (!isInner)
|
|
@@ -244,7 +533,7 @@ function getBoldDecorations({ decorations, node, view }) {
|
|
|
244
533
|
range: [node.from - step, node.to + step],
|
|
245
534
|
}));
|
|
246
535
|
}
|
|
247
|
-
function getBoldSelectionDecorations({ decorations, node, view,
|
|
536
|
+
function getBoldSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
248
537
|
if (node.name !== NAME_OF_BOLD) {
|
|
249
538
|
return;
|
|
250
539
|
}
|
|
@@ -252,7 +541,7 @@ function getBoldSelectionDecorations({ decorations, node, view, isReadonly, }) {
|
|
|
252
541
|
language.syntaxTree(view.state).resolve(node.from - 1).type.name !== "Emphasis") {
|
|
253
542
|
return;
|
|
254
543
|
}
|
|
255
|
-
if (
|
|
544
|
+
if (forceActive ||
|
|
256
545
|
!view.hasFocus ||
|
|
257
546
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
258
547
|
decorations.push(getHideDecoration({ range: [node.from, node.from + 2] }));
|
|
@@ -286,34 +575,34 @@ class CodeWidget extends view.WidgetType {
|
|
|
286
575
|
const button = this.button;
|
|
287
576
|
clearTimeout(this.timer);
|
|
288
577
|
button.classList.remove(styles.pending);
|
|
289
|
-
button.classList.remove(
|
|
578
|
+
button.classList.remove(CLASSES.codeButtonPending);
|
|
290
579
|
button.classList.remove(styles.success);
|
|
291
|
-
button.classList.remove(
|
|
580
|
+
button.classList.remove(CLASSES.codeButtonSuccess);
|
|
292
581
|
button.classList.remove(styles.fail);
|
|
293
|
-
button.classList.remove(
|
|
582
|
+
button.classList.remove(CLASSES.codeButtonFail);
|
|
294
583
|
button.classList.add(styles.pending);
|
|
295
|
-
button.classList.add(
|
|
584
|
+
button.classList.add(CLASSES.codeButtonPending);
|
|
296
585
|
span.classList.add(styles.hide);
|
|
297
586
|
void copyToClipboard(this.content)
|
|
298
587
|
.then(() => {
|
|
299
588
|
button.classList.remove(styles.pending);
|
|
300
|
-
button.classList.remove(
|
|
589
|
+
button.classList.remove(CLASSES.codeButtonPending);
|
|
301
590
|
button.classList.add(styles.success);
|
|
302
|
-
button.classList.add(
|
|
591
|
+
button.classList.add(CLASSES.codeButtonSuccess);
|
|
303
592
|
this.timer = setTimeout(() => {
|
|
304
593
|
button.classList.remove(styles.success);
|
|
305
|
-
button.classList.remove(
|
|
594
|
+
button.classList.remove(CLASSES.codeButtonSuccess);
|
|
306
595
|
span.classList.remove(styles.hide);
|
|
307
596
|
}, 500);
|
|
308
597
|
})
|
|
309
598
|
.catch(() => {
|
|
310
599
|
button.classList.remove(styles.pending);
|
|
311
|
-
button.classList.remove(
|
|
600
|
+
button.classList.remove(CLASSES.codeButtonPending);
|
|
312
601
|
button.classList.add(styles.fail);
|
|
313
|
-
button.classList.add(
|
|
602
|
+
button.classList.add(CLASSES.codeButtonFail);
|
|
314
603
|
this.timer = setTimeout(() => {
|
|
315
604
|
button.classList.remove(styles.fail);
|
|
316
|
-
button.classList.remove(
|
|
605
|
+
button.classList.remove(CLASSES.codeButtonFail);
|
|
317
606
|
span.classList.remove(styles.hide);
|
|
318
607
|
}, 500);
|
|
319
608
|
});
|
|
@@ -323,11 +612,11 @@ class CodeWidget extends view.WidgetType {
|
|
|
323
612
|
this.view = view;
|
|
324
613
|
const span = document.createElement("span");
|
|
325
614
|
span.classList.add(styles.code__span);
|
|
326
|
-
span.classList.add(
|
|
615
|
+
span.classList.add(CLASSES.codeButtonSpan);
|
|
327
616
|
span.textContent = this.language;
|
|
328
617
|
const button = document.createElement("button");
|
|
329
618
|
button.classList.add(styles.code__button);
|
|
330
|
-
button.classList.add(
|
|
619
|
+
button.classList.add(CLASSES.codeButton);
|
|
331
620
|
if (this.content)
|
|
332
621
|
button.addEventListener("click", this.onClick.bind(this));
|
|
333
622
|
button.appendChild(span);
|
|
@@ -341,7 +630,7 @@ class CodeWidget extends view.WidgetType {
|
|
|
341
630
|
}
|
|
342
631
|
}
|
|
343
632
|
|
|
344
|
-
function getCodeSelectionDecorations({ decorations, node, view,
|
|
633
|
+
function getCodeSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
345
634
|
if (node.name !== NAME_OF_FENCED_CODE && node.name !== NAME_OF_INLINE_CODE) {
|
|
346
635
|
return;
|
|
347
636
|
}
|
|
@@ -404,18 +693,18 @@ function getCodeSelectionDecorations({ decorations, node, view, isReadonly, }) {
|
|
|
404
693
|
if (lines.length > 1) {
|
|
405
694
|
lines.forEach((line) => {
|
|
406
695
|
decorations.push(getLineDecoration({
|
|
407
|
-
style: clsx(styles.code__line,
|
|
696
|
+
style: clsx(styles.code__line, CLASSES.code),
|
|
408
697
|
range: [line.from],
|
|
409
698
|
}));
|
|
410
699
|
});
|
|
411
700
|
}
|
|
412
701
|
else {
|
|
413
702
|
decorations.push(getMarkDecoration({
|
|
414
|
-
style: clsx(styles.code__single,
|
|
703
|
+
style: clsx(styles.code__single, CLASSES.code),
|
|
415
704
|
range: [node.from, node.to],
|
|
416
705
|
}));
|
|
417
706
|
}
|
|
418
|
-
if (
|
|
707
|
+
if (forceActive ||
|
|
419
708
|
!view.hasFocus ||
|
|
420
709
|
(lines.length > 1 && !isOverlapLine) ||
|
|
421
710
|
(lines.length === 1 && !isInRange(view.state.selection.ranges, [node.from, node.to]))) {
|
|
@@ -461,7 +750,7 @@ function getHeaderDecorations({ decorations, node, view }) {
|
|
|
461
750
|
range: [view.lineBlockAt(node.from).from],
|
|
462
751
|
}));
|
|
463
752
|
}
|
|
464
|
-
function getHeaderSelectionDecorations({ decorations, node, view,
|
|
753
|
+
function getHeaderSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
465
754
|
const isHeader = node.name.startsWith(NAME_OF_HEADER);
|
|
466
755
|
const isHeaderUnder = node.name.startsWith(NAME_OF_HEADER_UNDER);
|
|
467
756
|
if (!isHeader && !isHeaderUnder) {
|
|
@@ -474,7 +763,7 @@ function getHeaderSelectionDecorations({ decorations, node, view, isReadonly, })
|
|
|
474
763
|
const line = view.lineBlockAt(mark.from);
|
|
475
764
|
if (line.length < mark.to - mark.from + 1)
|
|
476
765
|
return;
|
|
477
|
-
if (
|
|
766
|
+
if (forceActive ||
|
|
478
767
|
!view.hasFocus ||
|
|
479
768
|
!isInRange(view.state.selection.ranges, [line.from, line.to])) {
|
|
480
769
|
decorations.push(getHideDecoration({ range: [mark.from, mark.to + 1] }));
|
|
@@ -483,7 +772,7 @@ function getHeaderSelectionDecorations({ decorations, node, view, isReadonly, })
|
|
|
483
772
|
else {
|
|
484
773
|
const lineHeader = view.lineBlockAt(node.from);
|
|
485
774
|
const lineMark = view.lineBlockAt(mark.from);
|
|
486
|
-
if (
|
|
775
|
+
if (forceActive ||
|
|
487
776
|
!view.hasFocus ||
|
|
488
777
|
!isInRange(view.state.selection.ranges, [lineHeader.from, lineMark.to])) {
|
|
489
778
|
decorations.push(getHideDecoration({ range: [lineMark.from, lineMark.to] }));
|
|
@@ -497,15 +786,15 @@ const headerDecorationPlugin = {
|
|
|
497
786
|
|
|
498
787
|
const NAME_OF_HORIZONTAL = "HorizontalRule";
|
|
499
788
|
|
|
500
|
-
function getHorizontalSelectionDecoration({ decorations,
|
|
789
|
+
function getHorizontalSelectionDecoration({ decorations, forceActive, node, view, }) {
|
|
501
790
|
if (node.name !== NAME_OF_HORIZONTAL)
|
|
502
791
|
return;
|
|
503
792
|
const line = view.lineBlockAt(node.from);
|
|
504
|
-
if (
|
|
793
|
+
if (forceActive ||
|
|
505
794
|
!view.hasFocus ||
|
|
506
795
|
!isInRange(view.state.selection.ranges, [line.from, line.to])) {
|
|
507
796
|
decorations.push(getLineDecoration({
|
|
508
|
-
style: clsx(styles.horizontal,
|
|
797
|
+
style: clsx(styles.horizontal, CLASSES.horizontal),
|
|
509
798
|
range: [line.from],
|
|
510
799
|
}));
|
|
511
800
|
decorations.push(getHideDecoration({ range: [node.from, node.to] }));
|
|
@@ -515,6 +804,31 @@ const horizontalDecorationPlugin = {
|
|
|
515
804
|
selectionDecorations: [getHorizontalSelectionDecoration],
|
|
516
805
|
};
|
|
517
806
|
|
|
807
|
+
const openedImageEffect = state.StateEffect.define();
|
|
808
|
+
const openedLinkEffect = state.StateEffect.define();
|
|
809
|
+
const imageSrcGetterEffect = state.StateEffect.define();
|
|
810
|
+
const markdownState = state.StateField.define({
|
|
811
|
+
create() {
|
|
812
|
+
return {
|
|
813
|
+
openedImage: undefined,
|
|
814
|
+
imageSrcGetter: undefined,
|
|
815
|
+
openedLink: undefined,
|
|
816
|
+
};
|
|
817
|
+
},
|
|
818
|
+
update(value, transaction) {
|
|
819
|
+
const newValue = { ...value };
|
|
820
|
+
for (const effect of transaction.effects) {
|
|
821
|
+
if (effect.is(openedImageEffect))
|
|
822
|
+
newValue.openedImage = effect.value;
|
|
823
|
+
if (effect.is(imageSrcGetterEffect))
|
|
824
|
+
newValue.imageSrcGetter = effect.value;
|
|
825
|
+
if (effect.is(openedLinkEffect))
|
|
826
|
+
newValue.openedLink = effect.value;
|
|
827
|
+
}
|
|
828
|
+
return newValue;
|
|
829
|
+
},
|
|
830
|
+
});
|
|
831
|
+
|
|
518
832
|
const NAME_OF_IMAGE = "Image";
|
|
519
833
|
const CODE_OF_START_IMAGE_TEXT = 91; // [
|
|
520
834
|
const CODE_OF_END_IMAGE_TEXT = 93; // ]
|
|
@@ -530,29 +844,38 @@ class ImageWidget extends view.WidgetType {
|
|
|
530
844
|
link;
|
|
531
845
|
from;
|
|
532
846
|
to;
|
|
847
|
+
imageSrcGetter;
|
|
533
848
|
view;
|
|
534
|
-
constructor(text, link, from, to) {
|
|
849
|
+
constructor(text, link, from, to, imageSrcGetter, view) {
|
|
535
850
|
super();
|
|
536
851
|
this.text = text;
|
|
537
852
|
this.link = link;
|
|
538
853
|
this.from = from;
|
|
539
854
|
this.to = to;
|
|
855
|
+
this.imageSrcGetter = imageSrcGetter;
|
|
856
|
+
this.view = view;
|
|
540
857
|
}
|
|
541
858
|
get key() {
|
|
542
859
|
return `${this.link}:${this.text}:${this.from}:${this.to}`;
|
|
543
860
|
}
|
|
861
|
+
get src() {
|
|
862
|
+
return this.imageSrcGetter ? this.imageSrcGetter(this.link) : this.link;
|
|
863
|
+
}
|
|
544
864
|
eq(widget) {
|
|
545
865
|
const image = IMAGE_NODES[this.key];
|
|
866
|
+
if (!image)
|
|
867
|
+
return false;
|
|
546
868
|
delete IMAGE_NODES[this.key];
|
|
547
869
|
EXISTING_WIDGETS.delete(this.key);
|
|
548
|
-
if (image.src !== widget.
|
|
549
|
-
image.src = widget.
|
|
870
|
+
if (image.src !== widget.src)
|
|
871
|
+
image.src = widget.src;
|
|
550
872
|
if (image.alt !== widget.text)
|
|
551
873
|
image.alt = widget.text;
|
|
552
874
|
this.link = widget.link;
|
|
553
875
|
this.text = widget.text;
|
|
554
876
|
this.from = widget.from;
|
|
555
877
|
this.to = widget.to;
|
|
878
|
+
this.registerListeners(image);
|
|
556
879
|
IMAGE_NODES[this.key] = image;
|
|
557
880
|
EXISTING_WIDGETS.add(this.key);
|
|
558
881
|
return true;
|
|
@@ -560,24 +883,23 @@ class ImageWidget extends view.WidgetType {
|
|
|
560
883
|
updateDOM() {
|
|
561
884
|
return true;
|
|
562
885
|
}
|
|
563
|
-
toDOM(
|
|
886
|
+
toDOM() {
|
|
564
887
|
EXISTING_WIDGETS.add(this.key);
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (image.src !== this.
|
|
568
|
-
image.src = this.
|
|
888
|
+
let image = IMAGE_NODES[this.key];
|
|
889
|
+
if (image) {
|
|
890
|
+
if (image.src !== this.src) {
|
|
891
|
+
image.src = this.src;
|
|
569
892
|
}
|
|
570
893
|
if (image.alt !== this.text)
|
|
571
894
|
image.alt = this.text;
|
|
572
895
|
return image;
|
|
573
896
|
}
|
|
574
|
-
|
|
575
|
-
const image = document.createElement("img");
|
|
897
|
+
image = document.createElement("img");
|
|
576
898
|
image.classList.add(styles.image);
|
|
577
899
|
image.alt = this.text;
|
|
578
|
-
image.src = this.
|
|
579
|
-
image.
|
|
580
|
-
|
|
900
|
+
image.src = this.src;
|
|
901
|
+
image.style.maxWidth = "100%";
|
|
902
|
+
this.registerListeners(image);
|
|
581
903
|
IMAGE_NODES[this.key] = image;
|
|
582
904
|
if (!interval)
|
|
583
905
|
interval = setInterval(garbageCollectorInterval, INTERVAL_DELAY);
|
|
@@ -586,15 +908,25 @@ class ImageWidget extends view.WidgetType {
|
|
|
586
908
|
destroy() {
|
|
587
909
|
EXISTING_WIDGETS.delete(this.key);
|
|
588
910
|
}
|
|
911
|
+
registerListeners(image) {
|
|
912
|
+
image.clearListeners?.();
|
|
913
|
+
const abortController = new AbortController();
|
|
914
|
+
image.addEventListener("mousedown", (event) => handleClick$1(this.view, this.text, this.link, this.key, event), { signal: abortController.signal });
|
|
915
|
+
image.clearListeners = () => {
|
|
916
|
+
abortController.abort();
|
|
917
|
+
};
|
|
918
|
+
image.destroy = () => {
|
|
919
|
+
image.clearListeners?.();
|
|
920
|
+
image.remove();
|
|
921
|
+
};
|
|
922
|
+
}
|
|
589
923
|
}
|
|
590
924
|
function garbageCollectorInterval() {
|
|
591
925
|
for (const [key, node] of Object.entries(IMAGE_NODES)) {
|
|
592
|
-
if (EXISTING_WIDGETS.has(key))
|
|
926
|
+
if (EXISTING_WIDGETS.has(key) || !node)
|
|
593
927
|
continue;
|
|
594
928
|
delete IMAGE_NODES[key];
|
|
595
|
-
node.
|
|
596
|
-
node.removeEventListener("click", handleClick);
|
|
597
|
-
node.remove();
|
|
929
|
+
node.destroy?.();
|
|
598
930
|
}
|
|
599
931
|
if (Object.keys(IMAGE_NODES).length === 0 && interval) {
|
|
600
932
|
clearInterval(interval);
|
|
@@ -602,44 +934,45 @@ function garbageCollectorInterval() {
|
|
|
602
934
|
}
|
|
603
935
|
}
|
|
604
936
|
/** recursively find the link text node in line */
|
|
605
|
-
function getTextNode(
|
|
937
|
+
function getTextNode$1(text, link, key, line) {
|
|
938
|
+
if (!line)
|
|
939
|
+
return null;
|
|
940
|
+
const textNodeContainer = getTextNodeContainer$1(text, link, key, line);
|
|
941
|
+
if (!textNodeContainer)
|
|
942
|
+
return null;
|
|
943
|
+
for (const node of Array.from(textNodeContainer.childNodes)) {
|
|
944
|
+
if (isCorrectNode$1(text, link, node)) {
|
|
945
|
+
return node;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return null;
|
|
949
|
+
}
|
|
950
|
+
function getTextNodeContainer$1(text, link, key, line) {
|
|
606
951
|
if (!line)
|
|
607
952
|
return null;
|
|
608
|
-
const link = imageNode.src;
|
|
609
|
-
let textNode = null;
|
|
610
953
|
for (const node of Array.from(line.childNodes)) {
|
|
611
|
-
if (node.
|
|
612
|
-
|
|
613
|
-
if (innerNode) {
|
|
614
|
-
textNode = innerNode;
|
|
615
|
-
break;
|
|
616
|
-
}
|
|
617
|
-
continue;
|
|
954
|
+
if (node instanceof HTMLElement && node.getAttribute("data-id") === key) {
|
|
955
|
+
return node;
|
|
618
956
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
957
|
+
if (node.nodeType !== 3) {
|
|
958
|
+
const inner = getTextNodeContainer$1(text, link, key, node);
|
|
959
|
+
if (inner)
|
|
960
|
+
return inner;
|
|
623
961
|
}
|
|
624
962
|
}
|
|
625
|
-
return
|
|
963
|
+
return null;
|
|
626
964
|
}
|
|
627
|
-
function
|
|
628
|
-
const text = imageNode.alt || "";
|
|
629
|
-
const link = imageNode.src;
|
|
630
|
-
const startPosition = 4 + text.length;
|
|
631
|
-
const endPosition = startPosition + link.length + 1;
|
|
632
|
-
return endPosition;
|
|
633
|
-
}
|
|
634
|
-
function isCorrectNode(imageNode, node) {
|
|
965
|
+
function isCorrectNode$1(text, link, node) {
|
|
635
966
|
if (!node)
|
|
636
967
|
return false;
|
|
637
968
|
const textContent = node?.textContent;
|
|
638
|
-
|
|
639
|
-
|
|
969
|
+
return Boolean(node &&
|
|
970
|
+
textContent &&
|
|
971
|
+
node.nodeType === 3 &&
|
|
972
|
+
textContent.includes(link) &&
|
|
973
|
+
textContent.includes(text));
|
|
640
974
|
}
|
|
641
|
-
function selectLink({
|
|
642
|
-
const link = imageNode.src;
|
|
975
|
+
function selectLink$1({ link, node, selection, start }) {
|
|
643
976
|
const startPosition = start ?? (node.textContent?.indexOf?.(link) || 0);
|
|
644
977
|
const endPosition = startPosition + link.length;
|
|
645
978
|
const range = document.createRange();
|
|
@@ -648,7 +981,7 @@ function selectLink({ imageNode, node, selection, start }) {
|
|
|
648
981
|
selection.removeAllRanges();
|
|
649
982
|
selection.addRange(range);
|
|
650
983
|
}
|
|
651
|
-
function handleClick(event) {
|
|
984
|
+
function handleClick$1(view, text, link, key, event) {
|
|
652
985
|
const selection = window.getSelection();
|
|
653
986
|
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) {
|
|
654
987
|
return;
|
|
@@ -665,74 +998,66 @@ function handleClick(event) {
|
|
|
665
998
|
const editor = Array.from(document.querySelectorAll(".cm-editor")).find((element) => element.contains(target));
|
|
666
999
|
if (!selection || !editor || !parent)
|
|
667
1000
|
return;
|
|
668
|
-
const
|
|
669
|
-
let textNode = getTextNode(target, prevLine);
|
|
670
|
-
if (!textNode)
|
|
671
|
-
textNode = getTextNode(target, parent);
|
|
1001
|
+
const textNode = getTextNode$1(text, link, key, line);
|
|
672
1002
|
if (textNode) {
|
|
673
|
-
|
|
674
|
-
selectLink({ selection, imageNode: target, node: textNode });
|
|
675
|
-
return;
|
|
1003
|
+
return void selectLink$1({ selection, link, node: textNode });
|
|
676
1004
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
return isCorrectNode(target, textNode);
|
|
692
|
-
},
|
|
693
|
-
})
|
|
694
|
-
.then(() => {
|
|
695
|
-
const textNode = getTextNode(target, line);
|
|
696
|
-
if (isCorrectNode(target, textNode))
|
|
697
|
-
selectLink({ selection, imageNode: target, node: textNode });
|
|
1005
|
+
saveDispatch(() => {
|
|
1006
|
+
if (!view)
|
|
1007
|
+
return;
|
|
1008
|
+
view.dispatch(view.state.update({ effects: openedImageEffect.of(key) }));
|
|
1009
|
+
const textNode = getTextNode$1(text, link, key, line);
|
|
1010
|
+
if (textNode) {
|
|
1011
|
+
selectLink$1({ selection, link, node: textNode });
|
|
1012
|
+
}
|
|
1013
|
+
requestAnimationFrame(() => {
|
|
1014
|
+
saveDispatch(() => {
|
|
1015
|
+
if (view)
|
|
1016
|
+
view.dispatch(view.state.update({ effects: openedImageEffect.of(undefined) }));
|
|
1017
|
+
});
|
|
1018
|
+
});
|
|
698
1019
|
});
|
|
699
1020
|
return false;
|
|
700
1021
|
}
|
|
701
1022
|
|
|
702
|
-
function
|
|
1023
|
+
function getImageDecorations({ decorations, node, view }) {
|
|
703
1024
|
if (node.name !== NAME_OF_IMAGE) {
|
|
704
1025
|
return;
|
|
705
1026
|
}
|
|
706
1027
|
const { text, url } = parseInfo(view, node);
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
717
|
-
else {
|
|
718
|
-
decorations.push(getWidgetDecorationOptions({
|
|
719
|
-
range: [node.to + 1],
|
|
720
|
-
widget: new ImageWidget(text, url, node.from, node.to),
|
|
721
|
-
}));
|
|
722
|
-
}
|
|
1028
|
+
const imageSrcGetter = view.state.field(markdownState).imageSrcGetter;
|
|
1029
|
+
decorations.push(getWidgetDecorationOptions({
|
|
1030
|
+
range: [node.to],
|
|
1031
|
+
widget: new ImageWidget(text, url, node.from, node.to, imageSrcGetter, view),
|
|
1032
|
+
}));
|
|
1033
|
+
}
|
|
1034
|
+
function getImageSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1035
|
+
if (node.name !== NAME_OF_IMAGE) {
|
|
1036
|
+
return;
|
|
723
1037
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1038
|
+
const { text, url } = parseInfo(view, node);
|
|
1039
|
+
const openedImage = view.state.field(markdownState).openedImage;
|
|
1040
|
+
const key = `${url}:${text}:${node.from}:${node.to}`;
|
|
1041
|
+
const isOpened = openedImage && openedImage === key;
|
|
1042
|
+
if (isOpened) {
|
|
1043
|
+
return void decorations.push(getMarkDecoration({
|
|
728
1044
|
range: [node.from, node.to],
|
|
729
|
-
|
|
1045
|
+
attributes: {
|
|
1046
|
+
"data-id": key,
|
|
1047
|
+
},
|
|
730
1048
|
}));
|
|
731
1049
|
}
|
|
1050
|
+
if (forceActive ||
|
|
1051
|
+
!view.hasFocus ||
|
|
1052
|
+
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1053
|
+
decorations.push(getHideDecoration({ range: [node.from, node.to] }));
|
|
1054
|
+
}
|
|
732
1055
|
else {
|
|
733
|
-
decorations.push(
|
|
734
|
-
range: [node.to],
|
|
735
|
-
|
|
1056
|
+
decorations.push(getMarkDecoration({
|
|
1057
|
+
range: [node.from, node.to],
|
|
1058
|
+
attributes: {
|
|
1059
|
+
"data-id": key,
|
|
1060
|
+
},
|
|
736
1061
|
}));
|
|
737
1062
|
}
|
|
738
1063
|
}
|
|
@@ -765,6 +1090,7 @@ function parseInfo(view, node) {
|
|
|
765
1090
|
}
|
|
766
1091
|
const imageDecorationPlugin = {
|
|
767
1092
|
selectionDecorations: [getImageSelectionDecorations],
|
|
1093
|
+
decorations: [getImageDecorations],
|
|
768
1094
|
};
|
|
769
1095
|
|
|
770
1096
|
const NAME_OF_ITALIC = "Emphasis";
|
|
@@ -779,12 +1105,12 @@ function getItalicDecorations({ decorations, node }) {
|
|
|
779
1105
|
range: [node.from, node.to],
|
|
780
1106
|
}));
|
|
781
1107
|
}
|
|
782
|
-
function getItalicSelectionDecorations({ decorations, node, view,
|
|
1108
|
+
function getItalicSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
783
1109
|
if (node.name !== NAME_OF_ITALIC) {
|
|
784
1110
|
return;
|
|
785
1111
|
}
|
|
786
|
-
if (checkIsSeveralEmphasis({ decorations, node, view,
|
|
787
|
-
return void splitEmphasis({ decorations, node, view,
|
|
1112
|
+
if (checkIsSeveralEmphasis({ decorations, node, view, forceActive })) {
|
|
1113
|
+
return void splitEmphasis({ decorations, node, view, forceActive });
|
|
788
1114
|
}
|
|
789
1115
|
let step = 1;
|
|
790
1116
|
const startText = view.state.doc.sliceString(node.from, node.from + 3);
|
|
@@ -792,7 +1118,7 @@ function getItalicSelectionDecorations({ decorations, node, view, isReadonly, })
|
|
|
792
1118
|
LIST_OF_ITALIC_MARKS.has(startText.charCodeAt(1)) &&
|
|
793
1119
|
LIST_OF_ITALIC_MARKS.has(startText.charCodeAt(2)))
|
|
794
1120
|
step = 3;
|
|
795
|
-
if (
|
|
1121
|
+
if (forceActive ||
|
|
796
1122
|
!view.hasFocus ||
|
|
797
1123
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
798
1124
|
decorations.push(getHideDecoration({ range: [node.from, node.from + step] }));
|
|
@@ -813,7 +1139,7 @@ function checkIsSeveralEmphasis({ node, view }) {
|
|
|
813
1139
|
return true;
|
|
814
1140
|
return false;
|
|
815
1141
|
}
|
|
816
|
-
function splitEmphasis({ decorations, node, view,
|
|
1142
|
+
function splitEmphasis({ decorations, node, view, forceActive }) {
|
|
817
1143
|
const text = view.state.doc.sliceString(node.from, node.to);
|
|
818
1144
|
let marks = 0;
|
|
819
1145
|
let pos = 0;
|
|
@@ -826,13 +1152,13 @@ function splitEmphasis({ decorations, node, view, isReadonly }) {
|
|
|
826
1152
|
decorations,
|
|
827
1153
|
view,
|
|
828
1154
|
node: { ...node, name: node.name, from: node.from, to: node.from + pos },
|
|
829
|
-
|
|
1155
|
+
forceActive,
|
|
830
1156
|
});
|
|
831
1157
|
getItalicSelectionDecorations({
|
|
832
1158
|
decorations,
|
|
833
1159
|
view,
|
|
834
1160
|
node: { ...node, name: node.name, from: node.from + pos, to: node.to },
|
|
835
|
-
|
|
1161
|
+
forceActive,
|
|
836
1162
|
});
|
|
837
1163
|
}
|
|
838
1164
|
const italicDecorationPlugin = {
|
|
@@ -848,10 +1174,11 @@ const CODE_OF_END_LINK_URL = 41; // )
|
|
|
848
1174
|
const NAME_OF_AUTO_LINK = "Autolink";
|
|
849
1175
|
const CODE_OF_LINK_LABEL_END = 58; // :
|
|
850
1176
|
|
|
851
|
-
|
|
1177
|
+
// [label]:
|
|
1178
|
+
function getLinkLabelSelectionDecoration({ decorations, node, view, forceActive, }) {
|
|
852
1179
|
if (view.state.doc.sliceString(node.to, node.to + 1).charCodeAt(0) !== CODE_OF_LINK_LABEL_END)
|
|
853
1180
|
return;
|
|
854
|
-
if (
|
|
1181
|
+
if (forceActive ||
|
|
855
1182
|
!view.hasFocus ||
|
|
856
1183
|
!isInRange(view.state.selection.ranges, [node.from, node.to + 1])) {
|
|
857
1184
|
decorations.push(getMarkDecoration({
|
|
@@ -863,141 +1190,165 @@ function getLinkLabelSelectionDecoration({ decorations, node, view, isReadonly,
|
|
|
863
1190
|
}
|
|
864
1191
|
}
|
|
865
1192
|
|
|
1193
|
+
const LINK_NODES = {};
|
|
866
1194
|
class LinkWidget extends view.WidgetType {
|
|
867
1195
|
text;
|
|
868
1196
|
link;
|
|
869
|
-
|
|
1197
|
+
from;
|
|
1198
|
+
to;
|
|
870
1199
|
view;
|
|
871
|
-
constructor(text, link,
|
|
1200
|
+
constructor(text, link, from, to, view) {
|
|
872
1201
|
super();
|
|
873
1202
|
this.text = text;
|
|
874
1203
|
this.link = link;
|
|
875
|
-
this.
|
|
1204
|
+
this.from = from;
|
|
1205
|
+
this.to = to;
|
|
1206
|
+
this.view = view;
|
|
876
1207
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
if (node.nodeType !== 3) {
|
|
884
|
-
const innerNode = this.getTextNode(node);
|
|
885
|
-
if (innerNode) {
|
|
886
|
-
textNode = innerNode;
|
|
887
|
-
break;
|
|
888
|
-
}
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
const textContent = node.textContent;
|
|
892
|
-
if (textContent && textContent.includes(this.link)) {
|
|
893
|
-
textNode = node;
|
|
894
|
-
break;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
return textNode;
|
|
898
|
-
}
|
|
899
|
-
getMinLength() {
|
|
900
|
-
let startPosition = 0;
|
|
901
|
-
if (this.type === "link")
|
|
902
|
-
startPosition = 3 + this.text.length;
|
|
903
|
-
if (this.type === "auto")
|
|
904
|
-
startPosition = 1;
|
|
905
|
-
const endPosition = startPosition + this.link.length;
|
|
906
|
-
return endPosition;
|
|
907
|
-
}
|
|
908
|
-
/** check that the text node is correct node */
|
|
909
|
-
isCorrectNode(node) {
|
|
910
|
-
if (!node)
|
|
1208
|
+
get key() {
|
|
1209
|
+
return `${this.link}:${this.text}:${this.from}:${this.to}`;
|
|
1210
|
+
}
|
|
1211
|
+
eq(widget) {
|
|
1212
|
+
const anchor = LINK_NODES[this.key];
|
|
1213
|
+
if (!anchor)
|
|
911
1214
|
return false;
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
}
|
|
925
|
-
handleClick(event) {
|
|
926
|
-
if (!this.view)
|
|
927
|
-
return;
|
|
928
|
-
/** open the link if has special key or the view is readonly */
|
|
929
|
-
const contentEditable = this.view.contentDOM.getAttribute("contenteditable");
|
|
930
|
-
const isReadonly = !contentEditable || contentEditable === "false";
|
|
931
|
-
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey || isReadonly) {
|
|
932
|
-
if (event.type === "mousedown") {
|
|
933
|
-
const target = event.target;
|
|
934
|
-
window.open(target.href, "_blank");
|
|
935
|
-
}
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
event.stopPropagation();
|
|
939
|
-
event.preventDefault();
|
|
940
|
-
const target = event.target;
|
|
941
|
-
const parent = target.parentNode;
|
|
942
|
-
let line = parent;
|
|
943
|
-
/** recursively find line that contains link */
|
|
944
|
-
while (line && !line.classList.contains("cm-line")) {
|
|
945
|
-
line = line.parentNode;
|
|
946
|
-
}
|
|
947
|
-
const editor = this.view.dom.querySelector(".cm-content");
|
|
948
|
-
const selection = window.getSelection();
|
|
949
|
-
if (!selection || !editor || !parent)
|
|
950
|
-
return;
|
|
951
|
-
const range = document.createRange();
|
|
952
|
-
range.selectNode(target);
|
|
953
|
-
range.collapse(true);
|
|
954
|
-
selection.removeAllRanges();
|
|
955
|
-
selection.addRange(range);
|
|
956
|
-
/** trick for correct select the link by click when the view is not focused */
|
|
957
|
-
void tick({ delay: 0 }).then(() => {
|
|
958
|
-
if (selection && selection.anchorNode?.nodeType !== 3) {
|
|
959
|
-
selection.removeAllRanges();
|
|
960
|
-
selection.addRange(range);
|
|
961
|
-
}
|
|
962
|
-
});
|
|
963
|
-
/** wait for the widget to disappear and link will be visible */
|
|
964
|
-
void tick({
|
|
965
|
-
delay: 0,
|
|
966
|
-
maxDeep: 5,
|
|
967
|
-
delayGetter: (deep) => {
|
|
968
|
-
return deep > 1 ? 10 : 5;
|
|
969
|
-
},
|
|
970
|
-
recursiveCondition: () => {
|
|
971
|
-
const textNode = this.getTextNode(line);
|
|
972
|
-
return this.isCorrectNode(textNode);
|
|
973
|
-
},
|
|
974
|
-
})
|
|
975
|
-
.then(() => {
|
|
976
|
-
const textNode = this.getTextNode(line);
|
|
977
|
-
if (this.isCorrectNode(textNode))
|
|
978
|
-
this.selectLink(textNode, selection);
|
|
979
|
-
});
|
|
980
|
-
return false;
|
|
1215
|
+
delete LINK_NODES[this.key];
|
|
1216
|
+
if (anchor.href !== widget.link)
|
|
1217
|
+
anchor.href = widget.link;
|
|
1218
|
+
if (anchor.textContent !== widget.text)
|
|
1219
|
+
anchor.textContent = widget.text;
|
|
1220
|
+
this.link = widget.link;
|
|
1221
|
+
this.text = widget.text;
|
|
1222
|
+
this.from = widget.from;
|
|
1223
|
+
this.to = widget.to;
|
|
1224
|
+
this.registerListeners(anchor);
|
|
1225
|
+
LINK_NODES[this.key] = anchor;
|
|
1226
|
+
return true;
|
|
981
1227
|
}
|
|
982
|
-
toDOM(
|
|
983
|
-
this.view = view;
|
|
1228
|
+
toDOM() {
|
|
984
1229
|
const anchor = document.createElement("a");
|
|
985
1230
|
anchor.classList.add(styles.link);
|
|
986
|
-
anchor.classList.add(
|
|
1231
|
+
anchor.classList.add(CLASSES.link);
|
|
987
1232
|
anchor.target = "_blank";
|
|
988
1233
|
anchor.textContent = this.text;
|
|
989
1234
|
anchor.href = this.link;
|
|
990
|
-
|
|
991
|
-
|
|
1235
|
+
this.registerListeners(anchor);
|
|
1236
|
+
LINK_NODES[this.key] = anchor;
|
|
992
1237
|
return anchor;
|
|
993
1238
|
}
|
|
994
1239
|
destroy(dom) {
|
|
995
|
-
|
|
996
|
-
dom.
|
|
1240
|
+
delete LINK_NODES[this.key];
|
|
1241
|
+
dom.destroy?.();
|
|
1242
|
+
}
|
|
1243
|
+
registerListeners(anchor) {
|
|
1244
|
+
anchor.clearListeners?.();
|
|
1245
|
+
const abortController = new AbortController();
|
|
1246
|
+
anchor.addEventListener("mousedown", (event) => handleClick(this.view, this.text, this.link, this.key, event), { signal: abortController.signal });
|
|
1247
|
+
anchor.addEventListener("click", (e) => e.preventDefault(), { signal: abortController.signal });
|
|
1248
|
+
anchor.clearListeners = () => {
|
|
1249
|
+
abortController.abort();
|
|
1250
|
+
};
|
|
1251
|
+
anchor.destroy = () => {
|
|
1252
|
+
anchor.clearListeners?.();
|
|
1253
|
+
anchor.remove();
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
/** recursively find the link text node in line */
|
|
1258
|
+
function getTextNode(text, link, key, line) {
|
|
1259
|
+
if (!line)
|
|
1260
|
+
return null;
|
|
1261
|
+
const textNodeContainer = getTextNodeContainer(text, link, key, line);
|
|
1262
|
+
if (!textNodeContainer)
|
|
1263
|
+
return null;
|
|
1264
|
+
for (const node of Array.from(textNodeContainer.childNodes)) {
|
|
1265
|
+
if (isCorrectNode(text, link, node)) {
|
|
1266
|
+
return node;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
function getTextNodeContainer(text, link, key, line) {
|
|
1272
|
+
if (!line)
|
|
1273
|
+
return null;
|
|
1274
|
+
for (const node of Array.from(line.childNodes)) {
|
|
1275
|
+
if (node instanceof HTMLElement && node.getAttribute("data-id") === key) {
|
|
1276
|
+
return node;
|
|
1277
|
+
}
|
|
1278
|
+
if (node.nodeType !== 3) {
|
|
1279
|
+
const inner = getTextNodeContainer(text, link, key, node);
|
|
1280
|
+
if (inner)
|
|
1281
|
+
return inner;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return null;
|
|
1285
|
+
}
|
|
1286
|
+
function isCorrectNode(text, link, node) {
|
|
1287
|
+
if (!node)
|
|
1288
|
+
return false;
|
|
1289
|
+
const textContent = node?.textContent;
|
|
1290
|
+
return Boolean(node &&
|
|
1291
|
+
textContent &&
|
|
1292
|
+
node.nodeType === 3 &&
|
|
1293
|
+
textContent.includes(link) &&
|
|
1294
|
+
textContent.includes(text));
|
|
1295
|
+
}
|
|
1296
|
+
function selectLink({ link, node, selection, start }) {
|
|
1297
|
+
const startPosition = start ?? (node.textContent?.indexOf?.(link) || 0);
|
|
1298
|
+
const endPosition = startPosition + link.length;
|
|
1299
|
+
const range = document.createRange();
|
|
1300
|
+
range.setStart(node, startPosition);
|
|
1301
|
+
range.setEnd(node, endPosition);
|
|
1302
|
+
selection.removeAllRanges();
|
|
1303
|
+
selection.addRange(range);
|
|
1304
|
+
}
|
|
1305
|
+
function handleClick(view, text, link, key, event) {
|
|
1306
|
+
/** open the link if has special key or the view is readonly */
|
|
1307
|
+
const contentEditable = view.contentDOM.getAttribute("contenteditable");
|
|
1308
|
+
const forceActive = !contentEditable || contentEditable === "false";
|
|
1309
|
+
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey || forceActive) {
|
|
1310
|
+
if (event.type === "mousedown") {
|
|
1311
|
+
const target = event.target;
|
|
1312
|
+
window.open(target.href, "_blank");
|
|
1313
|
+
}
|
|
1314
|
+
return;
|
|
997
1315
|
}
|
|
1316
|
+
event.stopPropagation();
|
|
1317
|
+
event.preventDefault();
|
|
1318
|
+
const target = event.target;
|
|
1319
|
+
const parent = target.parentNode;
|
|
1320
|
+
let line = parent;
|
|
1321
|
+
/** recursively find line that contains link */
|
|
1322
|
+
while (line && !line.classList.contains("cm-line")) {
|
|
1323
|
+
line = line.parentNode;
|
|
1324
|
+
}
|
|
1325
|
+
const editor = Array.from(document.querySelectorAll(".cm-editor")).find((element) => element.contains(target));
|
|
1326
|
+
const selection = window.getSelection();
|
|
1327
|
+
if (!selection || !editor || !parent)
|
|
1328
|
+
return;
|
|
1329
|
+
const textNode = getTextNode(text, link, key, line);
|
|
1330
|
+
if (textNode) {
|
|
1331
|
+
return void selectLink({ selection, link, node: textNode });
|
|
1332
|
+
}
|
|
1333
|
+
saveDispatch(() => {
|
|
1334
|
+
if (!view)
|
|
1335
|
+
return;
|
|
1336
|
+
view.dispatch(view.state.update({ effects: openedLinkEffect.of(key) }));
|
|
1337
|
+
const textNode = getTextNode(text, link, key, line);
|
|
1338
|
+
if (textNode) {
|
|
1339
|
+
selectLink({ selection, link, node: textNode });
|
|
1340
|
+
}
|
|
1341
|
+
requestAnimationFrame(() => {
|
|
1342
|
+
saveDispatch(() => {
|
|
1343
|
+
if (view)
|
|
1344
|
+
view.dispatch(view.state.update({ effects: openedLinkEffect.of(undefined) }));
|
|
1345
|
+
});
|
|
1346
|
+
});
|
|
1347
|
+
});
|
|
1348
|
+
return false;
|
|
998
1349
|
}
|
|
999
1350
|
|
|
1000
|
-
function getLinkSelectionDecorations({ decorations, node, view,
|
|
1351
|
+
function getLinkSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1001
1352
|
if (node.name !== NAME_OF_LINK) {
|
|
1002
1353
|
return;
|
|
1003
1354
|
}
|
|
@@ -1024,15 +1375,34 @@ function getLinkSelectionDecorations({ decorations, node, view, isReadonly, }) {
|
|
|
1024
1375
|
urlCoordinates.to = pos;
|
|
1025
1376
|
}
|
|
1026
1377
|
if (urlCoordinates.from === -1 || urlCoordinates.to === -1)
|
|
1027
|
-
return void getLinkLabelSelectionDecoration({ decorations,
|
|
1378
|
+
return void getLinkLabelSelectionDecoration({ decorations, forceActive, node, view });
|
|
1028
1379
|
const text = content.substring(textCoordinates.from, textCoordinates.to);
|
|
1029
1380
|
const url = content.substring(urlCoordinates.from, urlCoordinates.to);
|
|
1030
|
-
|
|
1381
|
+
const openedLink = view.state.field(markdownState).openedLink;
|
|
1382
|
+
const key = `${url}:${text}:${node.from}:${node.to}`;
|
|
1383
|
+
const isOpened = openedLink && openedLink === key;
|
|
1384
|
+
if (isOpened) {
|
|
1385
|
+
return void decorations.push(getMarkDecoration({
|
|
1386
|
+
range: [node.from, node.to],
|
|
1387
|
+
attributes: {
|
|
1388
|
+
"data-id": key,
|
|
1389
|
+
},
|
|
1390
|
+
}));
|
|
1391
|
+
}
|
|
1392
|
+
if (forceActive ||
|
|
1031
1393
|
!view.hasFocus ||
|
|
1032
1394
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1033
1395
|
decorations.push(getReplaceDecoration({
|
|
1034
1396
|
range: [node.from, node.to],
|
|
1035
|
-
widget: new LinkWidget(text, url,
|
|
1397
|
+
widget: new LinkWidget(text, url, node.from, node.to, view),
|
|
1398
|
+
}));
|
|
1399
|
+
}
|
|
1400
|
+
else {
|
|
1401
|
+
decorations.push(getMarkDecoration({
|
|
1402
|
+
range: [node.from, node.to],
|
|
1403
|
+
attributes: {
|
|
1404
|
+
"data-id": key,
|
|
1405
|
+
},
|
|
1036
1406
|
}));
|
|
1037
1407
|
}
|
|
1038
1408
|
}
|
|
@@ -1040,16 +1410,35 @@ const linkDecorationPlugin = {
|
|
|
1040
1410
|
selectionDecorations: [getLinkSelectionDecorations],
|
|
1041
1411
|
};
|
|
1042
1412
|
|
|
1043
|
-
function getAutoLinkSelectionDecorations({ decorations, node, view,
|
|
1413
|
+
function getAutoLinkSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1044
1414
|
if (node.name !== NAME_OF_AUTO_LINK)
|
|
1045
1415
|
return;
|
|
1046
1416
|
const url = view.state.doc.sliceString(node.from + 1, node.to - 1);
|
|
1047
|
-
|
|
1417
|
+
const openedLink = view.state.field(markdownState).openedLink;
|
|
1418
|
+
const key = `${url}:${url}:${node.from}:${node.to}`;
|
|
1419
|
+
const isOpened = openedLink && openedLink === key;
|
|
1420
|
+
if (isOpened) {
|
|
1421
|
+
return void decorations.push(getMarkDecoration({
|
|
1422
|
+
range: [node.from, node.to],
|
|
1423
|
+
attributes: {
|
|
1424
|
+
"data-id": key,
|
|
1425
|
+
},
|
|
1426
|
+
}));
|
|
1427
|
+
}
|
|
1428
|
+
if (forceActive ||
|
|
1048
1429
|
!view.hasFocus ||
|
|
1049
1430
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1050
1431
|
decorations.push(getReplaceDecoration({
|
|
1051
1432
|
range: [node.from, node.to],
|
|
1052
|
-
widget: new LinkWidget(url, url,
|
|
1433
|
+
widget: new LinkWidget(url, url, node.from, node.to, view),
|
|
1434
|
+
}));
|
|
1435
|
+
}
|
|
1436
|
+
else {
|
|
1437
|
+
decorations.push(getMarkDecoration({
|
|
1438
|
+
range: [node.from, node.to],
|
|
1439
|
+
attributes: {
|
|
1440
|
+
"data-id": key,
|
|
1441
|
+
},
|
|
1053
1442
|
}));
|
|
1054
1443
|
}
|
|
1055
1444
|
}
|
|
@@ -1076,7 +1465,7 @@ class ListPointWidget extends view.WidgetType {
|
|
|
1076
1465
|
span.textContent = this.mark;
|
|
1077
1466
|
if (LIST_OF_LIST_MARKS.has(this.lastCodePoint)) {
|
|
1078
1467
|
span.classList.add(styles.common);
|
|
1079
|
-
span.classList.add(
|
|
1468
|
+
span.classList.add(CLASSES.listCommon);
|
|
1080
1469
|
}
|
|
1081
1470
|
if (CODE_OF_ORDERED_LIST_MARK === this.lastCodePoint) {
|
|
1082
1471
|
span.classList.add(styles.ordered);
|
|
@@ -1085,7 +1474,7 @@ class ListPointWidget extends view.WidgetType {
|
|
|
1085
1474
|
}
|
|
1086
1475
|
}
|
|
1087
1476
|
|
|
1088
|
-
function getListSelectionDecorations({ decorations, node, view,
|
|
1477
|
+
function getListSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1089
1478
|
if (node.name !== NAME_OF_LIST) {
|
|
1090
1479
|
return;
|
|
1091
1480
|
}
|
|
@@ -1096,14 +1485,14 @@ function getListSelectionDecorations({ decorations, node, view, isReadonly, }) {
|
|
|
1096
1485
|
}
|
|
1097
1486
|
const nextSibling = node.node.nextSibling;
|
|
1098
1487
|
if (nextSibling && nextSibling.name === NAME_OF_TODO$1) {
|
|
1099
|
-
if (
|
|
1488
|
+
if (forceActive ||
|
|
1100
1489
|
!view.hasFocus ||
|
|
1101
1490
|
!isInRange(view.state.selection.ranges, [node.from, nextSibling.from + 3])) {
|
|
1102
1491
|
decorations.push(getHideDecoration({ range: [node.from, nextSibling.from] }));
|
|
1103
1492
|
}
|
|
1104
1493
|
return;
|
|
1105
1494
|
}
|
|
1106
|
-
if (
|
|
1495
|
+
if (forceActive ||
|
|
1107
1496
|
!view.hasFocus ||
|
|
1108
1497
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1109
1498
|
decorations.push(getReplaceDecoration({
|
|
@@ -1125,15 +1514,15 @@ function getMentionDecorations({ decorations, node }) {
|
|
|
1125
1514
|
return;
|
|
1126
1515
|
}
|
|
1127
1516
|
decorations.push(getMarkDecoration({
|
|
1128
|
-
style: clsx(styles.mention,
|
|
1517
|
+
style: clsx(styles.mention, CLASSES.mention),
|
|
1129
1518
|
range: [node.from, node.to],
|
|
1130
1519
|
}));
|
|
1131
1520
|
}
|
|
1132
|
-
function getMentionSelectionDecorations({ decorations, node, view,
|
|
1521
|
+
function getMentionSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1133
1522
|
if (node.name !== NAME_OF_MENTION) {
|
|
1134
1523
|
return;
|
|
1135
1524
|
}
|
|
1136
|
-
if (
|
|
1525
|
+
if (forceActive ||
|
|
1137
1526
|
!view.hasFocus ||
|
|
1138
1527
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1139
1528
|
decorations.push(getHideDecoration({ range: [node.from, node.from + 1] }));
|
|
@@ -1155,11 +1544,11 @@ function getStrikeThroughDecorations({ decorations, node }) {
|
|
|
1155
1544
|
range: [node.from, node.to],
|
|
1156
1545
|
}));
|
|
1157
1546
|
}
|
|
1158
|
-
function getStrikeThroughSelectionDecorations({ decorations, node, view,
|
|
1547
|
+
function getStrikeThroughSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1159
1548
|
if (node.name !== NAME_OF_STRIKE_THROUGH) {
|
|
1160
1549
|
return;
|
|
1161
1550
|
}
|
|
1162
|
-
if (
|
|
1551
|
+
if (forceActive ||
|
|
1163
1552
|
!view.hasFocus ||
|
|
1164
1553
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1165
1554
|
decorations.push(getHideDecoration({ range: [node.from, node.from + 2] }));
|
|
@@ -1193,7 +1582,7 @@ class TodoWidget extends view.WidgetType {
|
|
|
1193
1582
|
to: this.position + 1,
|
|
1194
1583
|
insert: this.checked ? " " : "x",
|
|
1195
1584
|
};
|
|
1196
|
-
|
|
1585
|
+
saveDispatch(() => {
|
|
1197
1586
|
if (!this.view)
|
|
1198
1587
|
return;
|
|
1199
1588
|
this.view.dispatch(this.view.state.update({ changes: change }));
|
|
@@ -1223,14 +1612,14 @@ class TodoWidget extends view.WidgetType {
|
|
|
1223
1612
|
}
|
|
1224
1613
|
}
|
|
1225
1614
|
|
|
1226
|
-
function getTodoSelectionDecoration({ decorations, node, view,
|
|
1615
|
+
function getTodoSelectionDecoration({ decorations, node, view, forceActive, }) {
|
|
1227
1616
|
if (node.name !== NAME_OF_TODO)
|
|
1228
1617
|
return;
|
|
1229
1618
|
const prevSibling = node.node.prevSibling;
|
|
1230
1619
|
if (!prevSibling || prevSibling.name !== NAME_OF_LIST_MARK)
|
|
1231
1620
|
return;
|
|
1232
1621
|
const isChecked = LIST_OF_TODO_MARKS.has(view.state.doc.sliceString(node.from + 1, node.from + 2).codePointAt(0) || 0);
|
|
1233
|
-
if (
|
|
1622
|
+
if (forceActive ||
|
|
1234
1623
|
!view.hasFocus ||
|
|
1235
1624
|
!isInRange(view.state.selection.ranges, [prevSibling.from, node.from + 3])) {
|
|
1236
1625
|
decorations.push(getReplaceDecoration({
|
|
@@ -1240,7 +1629,7 @@ function getTodoSelectionDecoration({ decorations, node, view, isReadonly, }) {
|
|
|
1240
1629
|
}
|
|
1241
1630
|
if (isChecked) {
|
|
1242
1631
|
const line = view.lineBlockAt(node.from);
|
|
1243
|
-
if (
|
|
1632
|
+
if (forceActive ||
|
|
1244
1633
|
!view.hasFocus ||
|
|
1245
1634
|
!isInRange(view.state.selection.ranges, [line.from, line.to]))
|
|
1246
1635
|
decorations.push(getMarkDecoration({ style: styles.todo__checked, range: [node.from + 4, node.to] }));
|
|
@@ -1290,87 +1679,305 @@ const SKIP_MARKS = new Set([
|
|
|
1290
1679
|
"HeaderMark",
|
|
1291
1680
|
"TaskMarker",
|
|
1292
1681
|
]);
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1682
|
+
function createDecorationsGetter() {
|
|
1683
|
+
let markdownDecorationsCache = [];
|
|
1684
|
+
let markdownSelectionDecorationsCache = [];
|
|
1685
|
+
function getDecorations(view$1, isChanged, mouseReleased) {
|
|
1686
|
+
const processDecorations = isChanged;
|
|
1687
|
+
const processSelectionDecorations = isChanged || mouseReleased;
|
|
1688
|
+
const decorations = processDecorations ? [] : markdownDecorationsCache;
|
|
1689
|
+
const selectionDecorations = processSelectionDecorations
|
|
1690
|
+
? []
|
|
1691
|
+
: markdownSelectionDecorationsCache;
|
|
1692
|
+
const contentEditable = view$1.contentDOM.getAttribute("contenteditable");
|
|
1693
|
+
const isReadonly = !contentEditable || contentEditable === "false";
|
|
1694
|
+
for (const { from: fromVisible, to: toVisible } of view$1.visibleRanges) {
|
|
1695
|
+
language.syntaxTree(view$1.state).iterate({
|
|
1696
|
+
from: fromVisible,
|
|
1697
|
+
to: toVisible,
|
|
1698
|
+
enter: (node) => {
|
|
1699
|
+
if (SKIP_MARKS.has(node.name))
|
|
1700
|
+
return;
|
|
1701
|
+
/** Decoration by change content */
|
|
1702
|
+
if (processDecorations)
|
|
1703
|
+
decorationFunctions.forEach((f) => f({ decorations, node, view: view$1 }));
|
|
1704
|
+
/** Decoration by selection content */
|
|
1705
|
+
if (processSelectionDecorations)
|
|
1706
|
+
selectionDecorationFunctions.forEach((f) => f({
|
|
1707
|
+
decorations: selectionDecorations,
|
|
1708
|
+
node,
|
|
1709
|
+
view: view$1,
|
|
1710
|
+
forceActive: isReadonly,
|
|
1711
|
+
}));
|
|
1712
|
+
},
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
if (processDecorations) {
|
|
1716
|
+
markdownDecorationsCache = decorations;
|
|
1717
|
+
}
|
|
1718
|
+
if (processSelectionDecorations) {
|
|
1719
|
+
markdownSelectionDecorationsCache = selectionDecorations;
|
|
1720
|
+
}
|
|
1721
|
+
return view.Decoration.set([...decorations, ...selectionDecorations], true);
|
|
1322
1722
|
}
|
|
1323
|
-
return
|
|
1723
|
+
return getDecorations;
|
|
1324
1724
|
}
|
|
1325
|
-
const markdownDecorationPlugin =
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1725
|
+
const markdownDecorationPlugin = (stateConfig) => {
|
|
1726
|
+
return view.ViewPlugin.fromClass(class DecorationMarkdown {
|
|
1727
|
+
decorations;
|
|
1728
|
+
mouseReleased = true;
|
|
1729
|
+
dom;
|
|
1730
|
+
view;
|
|
1731
|
+
decorationGetter;
|
|
1732
|
+
constructor(view) {
|
|
1733
|
+
this.decorationGetter = createDecorationsGetter();
|
|
1734
|
+
this.decorations = this.decorationGetter(view, true, this.mouseReleased);
|
|
1735
|
+
this.dom = view.dom;
|
|
1736
|
+
this.view = view;
|
|
1737
|
+
document.addEventListener("mousedown", this.onMouseDown.bind(this));
|
|
1738
|
+
document.addEventListener("mouseup", this.onMouseUp.bind(this));
|
|
1739
|
+
saveDispatch(() => {
|
|
1740
|
+
this.view.dispatch(this.view.state.update({
|
|
1741
|
+
effects: [imageSrcGetterEffect.of(stateConfig.imageSrcGetter)],
|
|
1742
|
+
}));
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
update(update) {
|
|
1746
|
+
const isDocumentChanged = update.docChanged ||
|
|
1747
|
+
update.viewportChanged ||
|
|
1748
|
+
language.syntaxTree(update.startState) != language.syntaxTree(update.state);
|
|
1749
|
+
this.decorations = this.decorationGetter(update.view, isDocumentChanged, this.mouseReleased);
|
|
1750
|
+
}
|
|
1751
|
+
destroy() {
|
|
1752
|
+
document.removeEventListener("mousedown", this.onMouseDown.bind(this));
|
|
1753
|
+
document.removeEventListener("mouseup", this.onMouseUp.bind(this));
|
|
1754
|
+
}
|
|
1755
|
+
onMouseDown() {
|
|
1756
|
+
this.mouseReleased = false;
|
|
1757
|
+
}
|
|
1758
|
+
onMouseUp() {
|
|
1759
|
+
this.mouseReleased = true;
|
|
1760
|
+
if (this.view.state.selection.ranges[0].from !== this.view.state.selection.ranges[0].to) {
|
|
1761
|
+
saveDispatch(() => {
|
|
1762
|
+
this.view.dispatch(this.view.state.update({}));
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
}, {
|
|
1767
|
+
decorations: (plugin) => plugin.decorations,
|
|
1768
|
+
});
|
|
1359
1769
|
};
|
|
1360
1770
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1771
|
+
async function InitSettings({ readonly, vimMode, }) {
|
|
1772
|
+
let vimExtension = [];
|
|
1773
|
+
if (vimMode) {
|
|
1774
|
+
const { vim } = await import('@replit/codemirror-vim');
|
|
1775
|
+
vimExtension = [vim({ status: true }), view.drawSelection()];
|
|
1776
|
+
}
|
|
1364
1777
|
return [
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1778
|
+
ReadonlyCompartment.of(view.EditorView.editable.of(!readonly)),
|
|
1779
|
+
VimModeCompartment.of(vimExtension),
|
|
1780
|
+
commands.history(),
|
|
1781
|
+
];
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
const initExtensions = async ({ onBlur, onChange, onFocus, onEnter, onEscape, readonly = true, vimMode = false, multiCursorText, provider, theme = "light", dark, light, languages, keyMaps, defaultKeyMaps, imageSrcGetter, }) => {
|
|
1785
|
+
const multiCursorMode = Boolean(multiCursorText && provider);
|
|
1786
|
+
const asyncPlugins = await Promise.all([
|
|
1787
|
+
InitSettings({ readonly, vimMode }),
|
|
1788
|
+
initKeyMaps({
|
|
1789
|
+
onEnter,
|
|
1790
|
+
onEscape,
|
|
1791
|
+
multiCursorMode,
|
|
1792
|
+
keyMaps,
|
|
1793
|
+
vimMode,
|
|
1794
|
+
theme,
|
|
1795
|
+
dark,
|
|
1796
|
+
defaultKeyMaps,
|
|
1797
|
+
light,
|
|
1370
1798
|
}),
|
|
1371
|
-
|
|
1799
|
+
new Promise((resolve) => {
|
|
1800
|
+
void Promise.resolve().then(() => require('./index-CDtGUxs-.js')).then(({ initMarkdown }) => {
|
|
1801
|
+
resolve(initMarkdown({ languages, imageSrcGetter }));
|
|
1802
|
+
});
|
|
1803
|
+
}),
|
|
1804
|
+
]);
|
|
1805
|
+
const extensions = [
|
|
1806
|
+
...asyncPlugins,
|
|
1807
|
+
initTheme({ theme, dark, light }),
|
|
1808
|
+
initListeners({ onBlur, onChange, onFocus }),
|
|
1372
1809
|
];
|
|
1810
|
+
if (multiCursorText && provider) {
|
|
1811
|
+
const multiCursorModules = await Promise.all([import('yjs'), import('y-codemirror.next')]);
|
|
1812
|
+
const [{ UndoManager }, { yCollab }] = multiCursorModules;
|
|
1813
|
+
const undoManager = new UndoManager(multiCursorText);
|
|
1814
|
+
extensions.push(yCollab(multiCursorText, provider.awareness, { undoManager }));
|
|
1815
|
+
}
|
|
1816
|
+
return extensions;
|
|
1373
1817
|
};
|
|
1374
1818
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1819
|
+
async function initEditorProvider({ roomId, url, userName = "Anonymous", userColor, initialText, onStartProvider, }) {
|
|
1820
|
+
const { Doc } = await import('yjs');
|
|
1821
|
+
const { WebsocketProvider } = await import('y-websocket');
|
|
1822
|
+
const multiCursorDocument = new Doc();
|
|
1823
|
+
const multiCursorText = multiCursorDocument.getText(roomId);
|
|
1824
|
+
if (!userColor || !userColor.startsWith("#")) {
|
|
1825
|
+
// eslint-disable-next-line no-console
|
|
1826
|
+
console.warn("user color must be hex!");
|
|
1827
|
+
userColor = "#30bced";
|
|
1828
|
+
}
|
|
1829
|
+
const userColorLight = `${userColor.substring(0, 7)}33`;
|
|
1830
|
+
const provider = new WebsocketProvider(url, roomId, multiCursorDocument);
|
|
1831
|
+
provider.awareness.setLocalStateField("user", {
|
|
1832
|
+
name: userName,
|
|
1833
|
+
color: userColor,
|
|
1834
|
+
colorLight: userColorLight,
|
|
1835
|
+
});
|
|
1836
|
+
if (onStartProvider)
|
|
1837
|
+
provider.on("status", (event) => {
|
|
1838
|
+
onStartProvider(event?.status);
|
|
1839
|
+
});
|
|
1840
|
+
if (provider && multiCursorText)
|
|
1841
|
+
provider.on("sync", (isSynced) => {
|
|
1842
|
+
if (isSynced && !multiCursorText.length && initialText) {
|
|
1843
|
+
multiCursorText.insert(0, initialText);
|
|
1844
|
+
}
|
|
1845
|
+
});
|
|
1846
|
+
return { provider, multiCursorText };
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
async function initEditorState({ text, ...rest }) {
|
|
1850
|
+
const extensions = await initExtensions(rest);
|
|
1851
|
+
return state.EditorState.create({
|
|
1852
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
1853
|
+
doc: rest.multiCursorText ? rest.multiCursorText.toString() : text,
|
|
1854
|
+
extensions,
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
async function initEditor({ multiCursor, root, initialText, ...rest }) {
|
|
1859
|
+
let provider;
|
|
1860
|
+
let multiCursorText;
|
|
1861
|
+
if (multiCursor) {
|
|
1862
|
+
const editorProvider = await initEditorProvider({ ...multiCursor, initialText });
|
|
1863
|
+
provider = editorProvider.provider;
|
|
1864
|
+
multiCursorText = editorProvider.multiCursorText;
|
|
1865
|
+
}
|
|
1866
|
+
const state = await initEditorState({
|
|
1867
|
+
...rest,
|
|
1868
|
+
text: initialText || "",
|
|
1869
|
+
provider,
|
|
1870
|
+
multiCursorText,
|
|
1871
|
+
});
|
|
1872
|
+
const view$1 = new view.EditorView({
|
|
1873
|
+
state,
|
|
1874
|
+
parent: root,
|
|
1875
|
+
});
|
|
1876
|
+
return { view: view$1, provider };
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
class Editor {
|
|
1880
|
+
view;
|
|
1881
|
+
provider;
|
|
1882
|
+
arguments;
|
|
1883
|
+
constructor(options) {
|
|
1884
|
+
void initEditor(options).then((editor) => {
|
|
1885
|
+
this.view = editor.view;
|
|
1886
|
+
this.provider = editor.provider;
|
|
1887
|
+
});
|
|
1888
|
+
this.arguments = options;
|
|
1889
|
+
}
|
|
1890
|
+
focus = () => {
|
|
1891
|
+
if (!this.view)
|
|
1892
|
+
return;
|
|
1893
|
+
this.view.focus();
|
|
1894
|
+
};
|
|
1895
|
+
getContent = () => {
|
|
1896
|
+
if (!this.view)
|
|
1897
|
+
return;
|
|
1898
|
+
return this.view.state.doc.toString();
|
|
1899
|
+
};
|
|
1900
|
+
setContent = (content, position) => {
|
|
1901
|
+
if (!this.view)
|
|
1902
|
+
return;
|
|
1903
|
+
if (position == undefined) {
|
|
1904
|
+
const cursor = this.view.state.selection.main.head;
|
|
1905
|
+
position = cursor;
|
|
1906
|
+
}
|
|
1907
|
+
const transaction = this.view.state.update({
|
|
1908
|
+
changes: {
|
|
1909
|
+
from: position,
|
|
1910
|
+
insert: content,
|
|
1911
|
+
},
|
|
1912
|
+
});
|
|
1913
|
+
saveDispatch(() => {
|
|
1914
|
+
if (!this.view)
|
|
1915
|
+
return;
|
|
1916
|
+
this.view.dispatch(transaction);
|
|
1917
|
+
});
|
|
1918
|
+
};
|
|
1919
|
+
setReadonly = (readonly) => {
|
|
1920
|
+
saveDispatch(() => {
|
|
1921
|
+
if (!this.view)
|
|
1922
|
+
return;
|
|
1923
|
+
this.view.dispatch({
|
|
1924
|
+
effects: ReadonlyCompartment.reconfigure(view.EditorView.editable.of(!readonly)),
|
|
1925
|
+
});
|
|
1926
|
+
});
|
|
1927
|
+
};
|
|
1928
|
+
setTheme = (theme) => {
|
|
1929
|
+
saveDispatch(() => {
|
|
1930
|
+
if (!this.view)
|
|
1931
|
+
return;
|
|
1932
|
+
this.view.dispatch({
|
|
1933
|
+
effects: ThemeCompartment.reconfigure(theme === "dark"
|
|
1934
|
+
? getDarkTheme({
|
|
1935
|
+
dark: this.arguments.dark,
|
|
1936
|
+
light: this.arguments.light,
|
|
1937
|
+
theme,
|
|
1938
|
+
})
|
|
1939
|
+
: getLightTheme({
|
|
1940
|
+
dark: this.arguments.dark,
|
|
1941
|
+
light: this.arguments.light,
|
|
1942
|
+
theme,
|
|
1943
|
+
})),
|
|
1944
|
+
});
|
|
1945
|
+
});
|
|
1946
|
+
};
|
|
1947
|
+
setVimMode = async (mode) => {
|
|
1948
|
+
if (!this.view)
|
|
1949
|
+
return;
|
|
1950
|
+
const { vim } = await import('@replit/codemirror-vim');
|
|
1951
|
+
saveDispatch(() => {
|
|
1952
|
+
if (!this.view)
|
|
1953
|
+
return;
|
|
1954
|
+
this.view.dispatch({
|
|
1955
|
+
effects: VimModeCompartment.reconfigure(mode ? [vim({ status: true }), view.drawSelection()] : []),
|
|
1956
|
+
});
|
|
1957
|
+
});
|
|
1958
|
+
};
|
|
1959
|
+
setUserProvider = (name = "Anonymous", color = "#000000") => {
|
|
1960
|
+
if (!this.provider)
|
|
1961
|
+
return;
|
|
1962
|
+
this.provider.awareness.setLocalStateField("user", { name, color });
|
|
1963
|
+
};
|
|
1964
|
+
destroy = () => {
|
|
1965
|
+
saveDispatch(() => {
|
|
1966
|
+
if (!this.view)
|
|
1967
|
+
return;
|
|
1968
|
+
this.view.destroy();
|
|
1969
|
+
});
|
|
1970
|
+
saveDispatch(() => {
|
|
1971
|
+
if (this.provider)
|
|
1972
|
+
this.provider.destroy();
|
|
1973
|
+
});
|
|
1974
|
+
};
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
exports.CODE_OF_SPACE = CODE_OF_SPACE;
|
|
1978
|
+
exports.CODE_OF_START_MENTION = CODE_OF_START_MENTION;
|
|
1979
|
+
exports.Editor = Editor;
|
|
1980
|
+
exports.NAME_OF_MENTION = NAME_OF_MENTION;
|
|
1981
|
+
exports.markdownDecorationPlugin = markdownDecorationPlugin;
|
|
1982
|
+
exports.markdownState = markdownState;
|
|
1983
|
+
//# sourceMappingURL=index-CiorogHq.js.map
|