@krainovsd/markdown-editor 0.1.3 → 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-DPZa3gzd.js → index-CiorogHq.js} +973 -368
- 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 +76 -70
- 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-Czx0hvPo.js +0 -528
- package/lib/cjs/index-Czx0hvPo.js.map +0 -1
- package/lib/cjs/index-DPZa3gzd.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,31 +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];
|
|
546
866
|
if (!image)
|
|
547
867
|
return false;
|
|
548
868
|
delete IMAGE_NODES[this.key];
|
|
549
869
|
EXISTING_WIDGETS.delete(this.key);
|
|
550
|
-
if (image.src !== widget.
|
|
551
|
-
image.src = widget.
|
|
870
|
+
if (image.src !== widget.src)
|
|
871
|
+
image.src = widget.src;
|
|
552
872
|
if (image.alt !== widget.text)
|
|
553
873
|
image.alt = widget.text;
|
|
554
874
|
this.link = widget.link;
|
|
555
875
|
this.text = widget.text;
|
|
556
876
|
this.from = widget.from;
|
|
557
877
|
this.to = widget.to;
|
|
878
|
+
this.registerListeners(image);
|
|
558
879
|
IMAGE_NODES[this.key] = image;
|
|
559
880
|
EXISTING_WIDGETS.add(this.key);
|
|
560
881
|
return true;
|
|
@@ -562,24 +883,23 @@ class ImageWidget extends view.WidgetType {
|
|
|
562
883
|
updateDOM() {
|
|
563
884
|
return true;
|
|
564
885
|
}
|
|
565
|
-
toDOM(
|
|
886
|
+
toDOM() {
|
|
566
887
|
EXISTING_WIDGETS.add(this.key);
|
|
567
888
|
let image = IMAGE_NODES[this.key];
|
|
568
889
|
if (image) {
|
|
569
|
-
if (image.src !== this.
|
|
570
|
-
image.src = this.
|
|
890
|
+
if (image.src !== this.src) {
|
|
891
|
+
image.src = this.src;
|
|
571
892
|
}
|
|
572
893
|
if (image.alt !== this.text)
|
|
573
894
|
image.alt = this.text;
|
|
574
895
|
return image;
|
|
575
896
|
}
|
|
576
|
-
this.view = view;
|
|
577
897
|
image = document.createElement("img");
|
|
578
898
|
image.classList.add(styles.image);
|
|
579
899
|
image.alt = this.text;
|
|
580
|
-
image.src = this.
|
|
581
|
-
image.
|
|
582
|
-
|
|
900
|
+
image.src = this.src;
|
|
901
|
+
image.style.maxWidth = "100%";
|
|
902
|
+
this.registerListeners(image);
|
|
583
903
|
IMAGE_NODES[this.key] = image;
|
|
584
904
|
if (!interval)
|
|
585
905
|
interval = setInterval(garbageCollectorInterval, INTERVAL_DELAY);
|
|
@@ -588,15 +908,25 @@ class ImageWidget extends view.WidgetType {
|
|
|
588
908
|
destroy() {
|
|
589
909
|
EXISTING_WIDGETS.delete(this.key);
|
|
590
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
|
+
}
|
|
591
923
|
}
|
|
592
924
|
function garbageCollectorInterval() {
|
|
593
925
|
for (const [key, node] of Object.entries(IMAGE_NODES)) {
|
|
594
926
|
if (EXISTING_WIDGETS.has(key) || !node)
|
|
595
927
|
continue;
|
|
596
928
|
delete IMAGE_NODES[key];
|
|
597
|
-
node.
|
|
598
|
-
node.removeEventListener("click", handleClick);
|
|
599
|
-
node.remove();
|
|
929
|
+
node.destroy?.();
|
|
600
930
|
}
|
|
601
931
|
if (Object.keys(IMAGE_NODES).length === 0 && interval) {
|
|
602
932
|
clearInterval(interval);
|
|
@@ -604,44 +934,45 @@ function garbageCollectorInterval() {
|
|
|
604
934
|
}
|
|
605
935
|
}
|
|
606
936
|
/** recursively find the link text node in line */
|
|
607
|
-
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) {
|
|
608
951
|
if (!line)
|
|
609
952
|
return null;
|
|
610
|
-
const link = imageNode.src;
|
|
611
|
-
let textNode = null;
|
|
612
953
|
for (const node of Array.from(line.childNodes)) {
|
|
613
|
-
if (node.
|
|
614
|
-
|
|
615
|
-
if (innerNode) {
|
|
616
|
-
textNode = innerNode;
|
|
617
|
-
break;
|
|
618
|
-
}
|
|
619
|
-
continue;
|
|
954
|
+
if (node instanceof HTMLElement && node.getAttribute("data-id") === key) {
|
|
955
|
+
return node;
|
|
620
956
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
957
|
+
if (node.nodeType !== 3) {
|
|
958
|
+
const inner = getTextNodeContainer$1(text, link, key, node);
|
|
959
|
+
if (inner)
|
|
960
|
+
return inner;
|
|
625
961
|
}
|
|
626
962
|
}
|
|
627
|
-
return
|
|
628
|
-
}
|
|
629
|
-
function getMinLength(imageNode) {
|
|
630
|
-
const text = imageNode.alt || "";
|
|
631
|
-
const link = imageNode.src;
|
|
632
|
-
const startPosition = 4 + text.length;
|
|
633
|
-
const endPosition = startPosition + link.length + 1;
|
|
634
|
-
return endPosition;
|
|
963
|
+
return null;
|
|
635
964
|
}
|
|
636
|
-
function isCorrectNode(
|
|
965
|
+
function isCorrectNode$1(text, link, node) {
|
|
637
966
|
if (!node)
|
|
638
967
|
return false;
|
|
639
968
|
const textContent = node?.textContent;
|
|
640
|
-
|
|
641
|
-
|
|
969
|
+
return Boolean(node &&
|
|
970
|
+
textContent &&
|
|
971
|
+
node.nodeType === 3 &&
|
|
972
|
+
textContent.includes(link) &&
|
|
973
|
+
textContent.includes(text));
|
|
642
974
|
}
|
|
643
|
-
function selectLink({
|
|
644
|
-
const link = imageNode.src;
|
|
975
|
+
function selectLink$1({ link, node, selection, start }) {
|
|
645
976
|
const startPosition = start ?? (node.textContent?.indexOf?.(link) || 0);
|
|
646
977
|
const endPosition = startPosition + link.length;
|
|
647
978
|
const range = document.createRange();
|
|
@@ -650,7 +981,7 @@ function selectLink({ imageNode, node, selection, start }) {
|
|
|
650
981
|
selection.removeAllRanges();
|
|
651
982
|
selection.addRange(range);
|
|
652
983
|
}
|
|
653
|
-
function handleClick(event) {
|
|
984
|
+
function handleClick$1(view, text, link, key, event) {
|
|
654
985
|
const selection = window.getSelection();
|
|
655
986
|
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey) {
|
|
656
987
|
return;
|
|
@@ -667,74 +998,66 @@ function handleClick(event) {
|
|
|
667
998
|
const editor = Array.from(document.querySelectorAll(".cm-editor")).find((element) => element.contains(target));
|
|
668
999
|
if (!selection || !editor || !parent)
|
|
669
1000
|
return;
|
|
670
|
-
const
|
|
671
|
-
let textNode = getTextNode(target, prevLine);
|
|
672
|
-
if (!textNode)
|
|
673
|
-
textNode = getTextNode(target, parent);
|
|
1001
|
+
const textNode = getTextNode$1(text, link, key, line);
|
|
674
1002
|
if (textNode) {
|
|
675
|
-
|
|
676
|
-
selectLink({ selection, imageNode: target, node: textNode });
|
|
677
|
-
return;
|
|
1003
|
+
return void selectLink$1({ selection, link, node: textNode });
|
|
678
1004
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
return isCorrectNode(target, textNode);
|
|
694
|
-
},
|
|
695
|
-
})
|
|
696
|
-
.then(() => {
|
|
697
|
-
const textNode = getTextNode(target, line);
|
|
698
|
-
if (isCorrectNode(target, textNode))
|
|
699
|
-
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
|
+
});
|
|
700
1019
|
});
|
|
701
1020
|
return false;
|
|
702
1021
|
}
|
|
703
1022
|
|
|
704
|
-
function
|
|
1023
|
+
function getImageDecorations({ decorations, node, view }) {
|
|
705
1024
|
if (node.name !== NAME_OF_IMAGE) {
|
|
706
1025
|
return;
|
|
707
1026
|
}
|
|
708
1027
|
const { text, url } = parseInfo(view, node);
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
-
else {
|
|
720
|
-
decorations.push(getWidgetDecorationOptions({
|
|
721
|
-
range: [node.to + 1],
|
|
722
|
-
widget: new ImageWidget(text, url, node.from, node.to),
|
|
723
|
-
}));
|
|
724
|
-
}
|
|
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;
|
|
725
1037
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
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({
|
|
730
1044
|
range: [node.from, node.to],
|
|
731
|
-
|
|
1045
|
+
attributes: {
|
|
1046
|
+
"data-id": key,
|
|
1047
|
+
},
|
|
732
1048
|
}));
|
|
733
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
|
+
}
|
|
734
1055
|
else {
|
|
735
|
-
decorations.push(
|
|
736
|
-
range: [node.to],
|
|
737
|
-
|
|
1056
|
+
decorations.push(getMarkDecoration({
|
|
1057
|
+
range: [node.from, node.to],
|
|
1058
|
+
attributes: {
|
|
1059
|
+
"data-id": key,
|
|
1060
|
+
},
|
|
738
1061
|
}));
|
|
739
1062
|
}
|
|
740
1063
|
}
|
|
@@ -767,6 +1090,7 @@ function parseInfo(view, node) {
|
|
|
767
1090
|
}
|
|
768
1091
|
const imageDecorationPlugin = {
|
|
769
1092
|
selectionDecorations: [getImageSelectionDecorations],
|
|
1093
|
+
decorations: [getImageDecorations],
|
|
770
1094
|
};
|
|
771
1095
|
|
|
772
1096
|
const NAME_OF_ITALIC = "Emphasis";
|
|
@@ -781,12 +1105,12 @@ function getItalicDecorations({ decorations, node }) {
|
|
|
781
1105
|
range: [node.from, node.to],
|
|
782
1106
|
}));
|
|
783
1107
|
}
|
|
784
|
-
function getItalicSelectionDecorations({ decorations, node, view,
|
|
1108
|
+
function getItalicSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
785
1109
|
if (node.name !== NAME_OF_ITALIC) {
|
|
786
1110
|
return;
|
|
787
1111
|
}
|
|
788
|
-
if (checkIsSeveralEmphasis({ decorations, node, view,
|
|
789
|
-
return void splitEmphasis({ decorations, node, view,
|
|
1112
|
+
if (checkIsSeveralEmphasis({ decorations, node, view, forceActive })) {
|
|
1113
|
+
return void splitEmphasis({ decorations, node, view, forceActive });
|
|
790
1114
|
}
|
|
791
1115
|
let step = 1;
|
|
792
1116
|
const startText = view.state.doc.sliceString(node.from, node.from + 3);
|
|
@@ -794,7 +1118,7 @@ function getItalicSelectionDecorations({ decorations, node, view, isReadonly, })
|
|
|
794
1118
|
LIST_OF_ITALIC_MARKS.has(startText.charCodeAt(1)) &&
|
|
795
1119
|
LIST_OF_ITALIC_MARKS.has(startText.charCodeAt(2)))
|
|
796
1120
|
step = 3;
|
|
797
|
-
if (
|
|
1121
|
+
if (forceActive ||
|
|
798
1122
|
!view.hasFocus ||
|
|
799
1123
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
800
1124
|
decorations.push(getHideDecoration({ range: [node.from, node.from + step] }));
|
|
@@ -815,7 +1139,7 @@ function checkIsSeveralEmphasis({ node, view }) {
|
|
|
815
1139
|
return true;
|
|
816
1140
|
return false;
|
|
817
1141
|
}
|
|
818
|
-
function splitEmphasis({ decorations, node, view,
|
|
1142
|
+
function splitEmphasis({ decorations, node, view, forceActive }) {
|
|
819
1143
|
const text = view.state.doc.sliceString(node.from, node.to);
|
|
820
1144
|
let marks = 0;
|
|
821
1145
|
let pos = 0;
|
|
@@ -828,13 +1152,13 @@ function splitEmphasis({ decorations, node, view, isReadonly }) {
|
|
|
828
1152
|
decorations,
|
|
829
1153
|
view,
|
|
830
1154
|
node: { ...node, name: node.name, from: node.from, to: node.from + pos },
|
|
831
|
-
|
|
1155
|
+
forceActive,
|
|
832
1156
|
});
|
|
833
1157
|
getItalicSelectionDecorations({
|
|
834
1158
|
decorations,
|
|
835
1159
|
view,
|
|
836
1160
|
node: { ...node, name: node.name, from: node.from + pos, to: node.to },
|
|
837
|
-
|
|
1161
|
+
forceActive,
|
|
838
1162
|
});
|
|
839
1163
|
}
|
|
840
1164
|
const italicDecorationPlugin = {
|
|
@@ -850,10 +1174,11 @@ const CODE_OF_END_LINK_URL = 41; // )
|
|
|
850
1174
|
const NAME_OF_AUTO_LINK = "Autolink";
|
|
851
1175
|
const CODE_OF_LINK_LABEL_END = 58; // :
|
|
852
1176
|
|
|
853
|
-
|
|
1177
|
+
// [label]:
|
|
1178
|
+
function getLinkLabelSelectionDecoration({ decorations, node, view, forceActive, }) {
|
|
854
1179
|
if (view.state.doc.sliceString(node.to, node.to + 1).charCodeAt(0) !== CODE_OF_LINK_LABEL_END)
|
|
855
1180
|
return;
|
|
856
|
-
if (
|
|
1181
|
+
if (forceActive ||
|
|
857
1182
|
!view.hasFocus ||
|
|
858
1183
|
!isInRange(view.state.selection.ranges, [node.from, node.to + 1])) {
|
|
859
1184
|
decorations.push(getMarkDecoration({
|
|
@@ -865,141 +1190,165 @@ function getLinkLabelSelectionDecoration({ decorations, node, view, isReadonly,
|
|
|
865
1190
|
}
|
|
866
1191
|
}
|
|
867
1192
|
|
|
1193
|
+
const LINK_NODES = {};
|
|
868
1194
|
class LinkWidget extends view.WidgetType {
|
|
869
1195
|
text;
|
|
870
1196
|
link;
|
|
871
|
-
|
|
1197
|
+
from;
|
|
1198
|
+
to;
|
|
872
1199
|
view;
|
|
873
|
-
constructor(text, link,
|
|
1200
|
+
constructor(text, link, from, to, view) {
|
|
874
1201
|
super();
|
|
875
1202
|
this.text = text;
|
|
876
1203
|
this.link = link;
|
|
877
|
-
this.
|
|
1204
|
+
this.from = from;
|
|
1205
|
+
this.to = to;
|
|
1206
|
+
this.view = view;
|
|
878
1207
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (node.nodeType !== 3) {
|
|
886
|
-
const innerNode = this.getTextNode(node);
|
|
887
|
-
if (innerNode) {
|
|
888
|
-
textNode = innerNode;
|
|
889
|
-
break;
|
|
890
|
-
}
|
|
891
|
-
continue;
|
|
892
|
-
}
|
|
893
|
-
const textContent = node.textContent;
|
|
894
|
-
if (textContent && textContent.includes(this.link)) {
|
|
895
|
-
textNode = node;
|
|
896
|
-
break;
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
return textNode;
|
|
900
|
-
}
|
|
901
|
-
getMinLength() {
|
|
902
|
-
let startPosition = 0;
|
|
903
|
-
if (this.type === "link")
|
|
904
|
-
startPosition = 3 + this.text.length;
|
|
905
|
-
if (this.type === "auto")
|
|
906
|
-
startPosition = 1;
|
|
907
|
-
const endPosition = startPosition + this.link.length;
|
|
908
|
-
return endPosition;
|
|
909
|
-
}
|
|
910
|
-
/** check that the text node is correct node */
|
|
911
|
-
isCorrectNode(node) {
|
|
912
|
-
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)
|
|
913
1214
|
return false;
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
}
|
|
927
|
-
handleClick(event) {
|
|
928
|
-
if (!this.view)
|
|
929
|
-
return;
|
|
930
|
-
/** open the link if has special key or the view is readonly */
|
|
931
|
-
const contentEditable = this.view.contentDOM.getAttribute("contenteditable");
|
|
932
|
-
const isReadonly = !contentEditable || contentEditable === "false";
|
|
933
|
-
if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey || isReadonly) {
|
|
934
|
-
if (event.type === "mousedown") {
|
|
935
|
-
const target = event.target;
|
|
936
|
-
window.open(target.href, "_blank");
|
|
937
|
-
}
|
|
938
|
-
return;
|
|
939
|
-
}
|
|
940
|
-
event.stopPropagation();
|
|
941
|
-
event.preventDefault();
|
|
942
|
-
const target = event.target;
|
|
943
|
-
const parent = target.parentNode;
|
|
944
|
-
let line = parent;
|
|
945
|
-
/** recursively find line that contains link */
|
|
946
|
-
while (line && !line.classList.contains("cm-line")) {
|
|
947
|
-
line = line.parentNode;
|
|
948
|
-
}
|
|
949
|
-
const editor = this.view.dom.querySelector(".cm-content");
|
|
950
|
-
const selection = window.getSelection();
|
|
951
|
-
if (!selection || !editor || !parent)
|
|
952
|
-
return;
|
|
953
|
-
const range = document.createRange();
|
|
954
|
-
range.selectNode(target);
|
|
955
|
-
range.collapse(true);
|
|
956
|
-
selection.removeAllRanges();
|
|
957
|
-
selection.addRange(range);
|
|
958
|
-
/** trick for correct select the link by click when the view is not focused */
|
|
959
|
-
void tick({ delay: 0 }).then(() => {
|
|
960
|
-
if (selection && selection.anchorNode?.nodeType !== 3) {
|
|
961
|
-
selection.removeAllRanges();
|
|
962
|
-
selection.addRange(range);
|
|
963
|
-
}
|
|
964
|
-
});
|
|
965
|
-
/** wait for the widget to disappear and link will be visible */
|
|
966
|
-
void tick({
|
|
967
|
-
delay: 0,
|
|
968
|
-
maxDeep: 5,
|
|
969
|
-
delayGetter: (deep) => {
|
|
970
|
-
return deep > 1 ? 10 : 5;
|
|
971
|
-
},
|
|
972
|
-
recursiveCondition: () => {
|
|
973
|
-
const textNode = this.getTextNode(line);
|
|
974
|
-
return this.isCorrectNode(textNode);
|
|
975
|
-
},
|
|
976
|
-
})
|
|
977
|
-
.then(() => {
|
|
978
|
-
const textNode = this.getTextNode(line);
|
|
979
|
-
if (this.isCorrectNode(textNode))
|
|
980
|
-
this.selectLink(textNode, selection);
|
|
981
|
-
});
|
|
982
|
-
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;
|
|
983
1227
|
}
|
|
984
|
-
toDOM(
|
|
985
|
-
this.view = view;
|
|
1228
|
+
toDOM() {
|
|
986
1229
|
const anchor = document.createElement("a");
|
|
987
1230
|
anchor.classList.add(styles.link);
|
|
988
|
-
anchor.classList.add(
|
|
1231
|
+
anchor.classList.add(CLASSES.link);
|
|
989
1232
|
anchor.target = "_blank";
|
|
990
1233
|
anchor.textContent = this.text;
|
|
991
1234
|
anchor.href = this.link;
|
|
992
|
-
|
|
993
|
-
|
|
1235
|
+
this.registerListeners(anchor);
|
|
1236
|
+
LINK_NODES[this.key] = anchor;
|
|
994
1237
|
return anchor;
|
|
995
1238
|
}
|
|
996
1239
|
destroy(dom) {
|
|
997
|
-
|
|
998
|
-
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;
|
|
999
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;
|
|
1000
1349
|
}
|
|
1001
1350
|
|
|
1002
|
-
function getLinkSelectionDecorations({ decorations, node, view,
|
|
1351
|
+
function getLinkSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1003
1352
|
if (node.name !== NAME_OF_LINK) {
|
|
1004
1353
|
return;
|
|
1005
1354
|
}
|
|
@@ -1026,15 +1375,34 @@ function getLinkSelectionDecorations({ decorations, node, view, isReadonly, }) {
|
|
|
1026
1375
|
urlCoordinates.to = pos;
|
|
1027
1376
|
}
|
|
1028
1377
|
if (urlCoordinates.from === -1 || urlCoordinates.to === -1)
|
|
1029
|
-
return void getLinkLabelSelectionDecoration({ decorations,
|
|
1378
|
+
return void getLinkLabelSelectionDecoration({ decorations, forceActive, node, view });
|
|
1030
1379
|
const text = content.substring(textCoordinates.from, textCoordinates.to);
|
|
1031
1380
|
const url = content.substring(urlCoordinates.from, urlCoordinates.to);
|
|
1032
|
-
|
|
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 ||
|
|
1033
1393
|
!view.hasFocus ||
|
|
1034
1394
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1035
1395
|
decorations.push(getReplaceDecoration({
|
|
1036
1396
|
range: [node.from, node.to],
|
|
1037
|
-
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
|
+
},
|
|
1038
1406
|
}));
|
|
1039
1407
|
}
|
|
1040
1408
|
}
|
|
@@ -1042,16 +1410,35 @@ const linkDecorationPlugin = {
|
|
|
1042
1410
|
selectionDecorations: [getLinkSelectionDecorations],
|
|
1043
1411
|
};
|
|
1044
1412
|
|
|
1045
|
-
function getAutoLinkSelectionDecorations({ decorations, node, view,
|
|
1413
|
+
function getAutoLinkSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1046
1414
|
if (node.name !== NAME_OF_AUTO_LINK)
|
|
1047
1415
|
return;
|
|
1048
1416
|
const url = view.state.doc.sliceString(node.from + 1, node.to - 1);
|
|
1049
|
-
|
|
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 ||
|
|
1050
1429
|
!view.hasFocus ||
|
|
1051
1430
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1052
1431
|
decorations.push(getReplaceDecoration({
|
|
1053
1432
|
range: [node.from, node.to],
|
|
1054
|
-
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
|
+
},
|
|
1055
1442
|
}));
|
|
1056
1443
|
}
|
|
1057
1444
|
}
|
|
@@ -1078,7 +1465,7 @@ class ListPointWidget extends view.WidgetType {
|
|
|
1078
1465
|
span.textContent = this.mark;
|
|
1079
1466
|
if (LIST_OF_LIST_MARKS.has(this.lastCodePoint)) {
|
|
1080
1467
|
span.classList.add(styles.common);
|
|
1081
|
-
span.classList.add(
|
|
1468
|
+
span.classList.add(CLASSES.listCommon);
|
|
1082
1469
|
}
|
|
1083
1470
|
if (CODE_OF_ORDERED_LIST_MARK === this.lastCodePoint) {
|
|
1084
1471
|
span.classList.add(styles.ordered);
|
|
@@ -1087,7 +1474,7 @@ class ListPointWidget extends view.WidgetType {
|
|
|
1087
1474
|
}
|
|
1088
1475
|
}
|
|
1089
1476
|
|
|
1090
|
-
function getListSelectionDecorations({ decorations, node, view,
|
|
1477
|
+
function getListSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1091
1478
|
if (node.name !== NAME_OF_LIST) {
|
|
1092
1479
|
return;
|
|
1093
1480
|
}
|
|
@@ -1098,14 +1485,14 @@ function getListSelectionDecorations({ decorations, node, view, isReadonly, }) {
|
|
|
1098
1485
|
}
|
|
1099
1486
|
const nextSibling = node.node.nextSibling;
|
|
1100
1487
|
if (nextSibling && nextSibling.name === NAME_OF_TODO$1) {
|
|
1101
|
-
if (
|
|
1488
|
+
if (forceActive ||
|
|
1102
1489
|
!view.hasFocus ||
|
|
1103
1490
|
!isInRange(view.state.selection.ranges, [node.from, nextSibling.from + 3])) {
|
|
1104
1491
|
decorations.push(getHideDecoration({ range: [node.from, nextSibling.from] }));
|
|
1105
1492
|
}
|
|
1106
1493
|
return;
|
|
1107
1494
|
}
|
|
1108
|
-
if (
|
|
1495
|
+
if (forceActive ||
|
|
1109
1496
|
!view.hasFocus ||
|
|
1110
1497
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1111
1498
|
decorations.push(getReplaceDecoration({
|
|
@@ -1127,15 +1514,15 @@ function getMentionDecorations({ decorations, node }) {
|
|
|
1127
1514
|
return;
|
|
1128
1515
|
}
|
|
1129
1516
|
decorations.push(getMarkDecoration({
|
|
1130
|
-
style: clsx(styles.mention,
|
|
1517
|
+
style: clsx(styles.mention, CLASSES.mention),
|
|
1131
1518
|
range: [node.from, node.to],
|
|
1132
1519
|
}));
|
|
1133
1520
|
}
|
|
1134
|
-
function getMentionSelectionDecorations({ decorations, node, view,
|
|
1521
|
+
function getMentionSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1135
1522
|
if (node.name !== NAME_OF_MENTION) {
|
|
1136
1523
|
return;
|
|
1137
1524
|
}
|
|
1138
|
-
if (
|
|
1525
|
+
if (forceActive ||
|
|
1139
1526
|
!view.hasFocus ||
|
|
1140
1527
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1141
1528
|
decorations.push(getHideDecoration({ range: [node.from, node.from + 1] }));
|
|
@@ -1157,11 +1544,11 @@ function getStrikeThroughDecorations({ decorations, node }) {
|
|
|
1157
1544
|
range: [node.from, node.to],
|
|
1158
1545
|
}));
|
|
1159
1546
|
}
|
|
1160
|
-
function getStrikeThroughSelectionDecorations({ decorations, node, view,
|
|
1547
|
+
function getStrikeThroughSelectionDecorations({ decorations, node, view, forceActive, }) {
|
|
1161
1548
|
if (node.name !== NAME_OF_STRIKE_THROUGH) {
|
|
1162
1549
|
return;
|
|
1163
1550
|
}
|
|
1164
|
-
if (
|
|
1551
|
+
if (forceActive ||
|
|
1165
1552
|
!view.hasFocus ||
|
|
1166
1553
|
!isInRange(view.state.selection.ranges, [node.from, node.to])) {
|
|
1167
1554
|
decorations.push(getHideDecoration({ range: [node.from, node.from + 2] }));
|
|
@@ -1195,7 +1582,7 @@ class TodoWidget extends view.WidgetType {
|
|
|
1195
1582
|
to: this.position + 1,
|
|
1196
1583
|
insert: this.checked ? " " : "x",
|
|
1197
1584
|
};
|
|
1198
|
-
|
|
1585
|
+
saveDispatch(() => {
|
|
1199
1586
|
if (!this.view)
|
|
1200
1587
|
return;
|
|
1201
1588
|
this.view.dispatch(this.view.state.update({ changes: change }));
|
|
@@ -1225,14 +1612,14 @@ class TodoWidget extends view.WidgetType {
|
|
|
1225
1612
|
}
|
|
1226
1613
|
}
|
|
1227
1614
|
|
|
1228
|
-
function getTodoSelectionDecoration({ decorations, node, view,
|
|
1615
|
+
function getTodoSelectionDecoration({ decorations, node, view, forceActive, }) {
|
|
1229
1616
|
if (node.name !== NAME_OF_TODO)
|
|
1230
1617
|
return;
|
|
1231
1618
|
const prevSibling = node.node.prevSibling;
|
|
1232
1619
|
if (!prevSibling || prevSibling.name !== NAME_OF_LIST_MARK)
|
|
1233
1620
|
return;
|
|
1234
1621
|
const isChecked = LIST_OF_TODO_MARKS.has(view.state.doc.sliceString(node.from + 1, node.from + 2).codePointAt(0) || 0);
|
|
1235
|
-
if (
|
|
1622
|
+
if (forceActive ||
|
|
1236
1623
|
!view.hasFocus ||
|
|
1237
1624
|
!isInRange(view.state.selection.ranges, [prevSibling.from, node.from + 3])) {
|
|
1238
1625
|
decorations.push(getReplaceDecoration({
|
|
@@ -1242,7 +1629,7 @@ function getTodoSelectionDecoration({ decorations, node, view, isReadonly, }) {
|
|
|
1242
1629
|
}
|
|
1243
1630
|
if (isChecked) {
|
|
1244
1631
|
const line = view.lineBlockAt(node.from);
|
|
1245
|
-
if (
|
|
1632
|
+
if (forceActive ||
|
|
1246
1633
|
!view.hasFocus ||
|
|
1247
1634
|
!isInRange(view.state.selection.ranges, [line.from, line.to]))
|
|
1248
1635
|
decorations.push(getMarkDecoration({ style: styles.todo__checked, range: [node.from + 4, node.to] }));
|
|
@@ -1292,87 +1679,305 @@ const SKIP_MARKS = new Set([
|
|
|
1292
1679
|
"HeaderMark",
|
|
1293
1680
|
"TaskMarker",
|
|
1294
1681
|
]);
|
|
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
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
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);
|
|
1324
1722
|
}
|
|
1325
|
-
return
|
|
1723
|
+
return getDecorations;
|
|
1326
1724
|
}
|
|
1327
|
-
const markdownDecorationPlugin =
|
|
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
|
-
|
|
1359
|
-
}
|
|
1360
|
-
|
|
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
|
+
});
|
|
1361
1769
|
};
|
|
1362
1770
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
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
|
+
}
|
|
1366
1777
|
return [
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
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,
|
|
1372
1798
|
}),
|
|
1373
|
-
|
|
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 }),
|
|
1374
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;
|
|
1375
1817
|
};
|
|
1376
1818
|
|
|
1377
|
-
|
|
1378
|
-
|
|
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
|