@wonderwhy-er/desktop-commander 0.2.39 → 0.2.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.js +1 -1
- package/dist/ui/file-preview/preview-runtime.js +204 -153
- package/dist/ui/file-preview/src/markdown/controller.d.ts +7 -1
- package/dist/ui/file-preview/src/markdown/controller.js +135 -16
- package/dist/ui/file-preview/src/markdown/editor.d.ts +97 -1
- package/dist/ui/file-preview/src/markdown/editor.js +814 -26
- package/dist/ui/file-preview/src/model.d.ts +2 -1
- package/dist/utils/capture.js +1 -1
- package/dist/utils/toolHistory.d.ts +13 -0
- package/dist/utils/toolHistory.js +65 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -1
- package/dist/ui/config-editor/app.js +0 -840
- package/dist/ui/config-editor/array-modal.d.ts +0 -19
- package/dist/ui/config-editor/array-modal.js +0 -185
- package/dist/ui/config-editor/main.d.ts +0 -1
- package/dist/ui/config-editor/main.js +0 -2
- package/dist/ui/config-editor/src/App.d.ts +0 -43
- package/dist/ui/config-editor/src/components/layout.d.ts +0 -4
- package/dist/ui/config-editor/src/components/layout.js +0 -83
- package/dist/ui/config-editor/src/components/toolbar.d.ts +0 -1
- package/dist/ui/config-editor/src/components/toolbar.js +0 -21
- package/dist/ui/config-editor/src/config-values.d.ts +0 -6
- package/dist/ui/config-editor/src/config-values.js +0 -61
- package/dist/ui/config-editor/src/contracts.d.ts +0 -14
- package/dist/ui/config-editor/src/contracts.js +0 -3
- package/dist/ui/config-editor/src/directory-browser.d.ts +0 -6
- package/dist/ui/config-editor/src/directory-browser.js +0 -71
- package/dist/ui/config-editor/src/layout.d.ts +0 -5
- package/dist/ui/config-editor/src/layout.js +0 -90
- package/dist/ui/config-editor/src/parsing.d.ts +0 -5
- package/dist/ui/config-editor/src/parsing.js +0 -50
- package/dist/ui/config-editor/src/toolbar.d.ts +0 -1
- package/dist/ui/config-editor/src/toolbar.js +0 -18
- package/dist/ui/config-editor/src/types.d.ts +0 -17
- package/dist/ui/config-editor/src/types.js +0 -3
- package/dist/ui/config-editor/src/utils/config-values.d.ts +0 -9
- package/dist/ui/config-editor/src/utils/config-values.js +0 -61
- package/dist/ui/config-editor/src/utils/directory-browser.d.ts +0 -31
- package/dist/ui/config-editor/src/utils/directory-browser.js +0 -201
- package/dist/ui/config-editor/src/utils/parsing.d.ts +0 -8
- package/dist/ui/config-editor/src/utils/parsing.js +0 -50
- package/dist/ui/file-preview/app.d.ts +0 -8
- package/dist/ui/file-preview/app.js +0 -2020
- package/dist/ui/file-preview/components/code-viewer.d.ts +0 -6
- package/dist/ui/file-preview/components/code-viewer.js +0 -73
- package/dist/ui/file-preview/components/highlighting.d.ts +0 -2
- package/dist/ui/file-preview/components/highlighting.js +0 -54
- package/dist/ui/file-preview/components/html-renderer.d.ts +0 -5
- package/dist/ui/file-preview/components/html-renderer.js +0 -47
- package/dist/ui/file-preview/components/markdown-renderer.d.ts +0 -1
- package/dist/ui/file-preview/components/markdown-renderer.js +0 -67
- package/dist/ui/file-preview/components/toolbar.d.ts +0 -6
- package/dist/ui/file-preview/components/toolbar.js +0 -75
- package/dist/ui/file-preview/image-preview.d.ts +0 -3
- package/dist/ui/file-preview/image-preview.js +0 -21
- package/dist/ui/file-preview/main.d.ts +0 -1
- package/dist/ui/file-preview/main.js +0 -5
- package/dist/ui/file-preview/markdown/editor.d.ts +0 -36
- package/dist/ui/file-preview/markdown/editor.js +0 -643
- package/dist/ui/file-preview/markdown/linking.d.ts +0 -9
- package/dist/ui/file-preview/markdown/linking.js +0 -210
- package/dist/ui/file-preview/markdown/outline.d.ts +0 -7
- package/dist/ui/file-preview/markdown/outline.js +0 -40
- package/dist/ui/file-preview/markdown/preview.d.ts +0 -8
- package/dist/ui/file-preview/markdown/preview.js +0 -33
- package/dist/ui/file-preview/markdown/slugify.d.ts +0 -3
- package/dist/ui/file-preview/markdown/slugify.js +0 -31
- package/dist/ui/file-preview/markdown/toc.d.ts +0 -11
- package/dist/ui/file-preview/markdown/toc.js +0 -75
- package/dist/ui/file-preview/markdown/utils.d.ts +0 -1
- package/dist/ui/file-preview/markdown/utils.js +0 -15
- package/dist/ui/file-preview/markdown/workspace-controller.d.ts +0 -25
- package/dist/ui/file-preview/markdown/workspace-controller.js +0 -40
- package/dist/ui/file-preview/src/components/CodeViewer.d.ts +0 -6
- package/dist/ui/file-preview/src/components/CodeViewer.js +0 -60
- package/dist/ui/file-preview/src/components/HtmlRenderer.d.ts +0 -8
- package/dist/ui/file-preview/src/components/HtmlRenderer.js +0 -45
- package/dist/ui/file-preview/src/components/MarkdownRenderer.d.ts +0 -1
- package/dist/ui/file-preview/src/components/MarkdownRenderer.js +0 -15
- package/dist/ui/file-preview/src/components/Toolbar.d.ts +0 -6
- package/dist/ui/file-preview/src/components/Toolbar.js +0 -75
- package/dist/ui/file-preview/src/components/editor-toolbar.d.ts +0 -15
- package/dist/ui/file-preview/src/components/editor-toolbar.js +0 -384
- package/dist/ui/file-preview/src/components/markdown-editor.d.ts +0 -29
- package/dist/ui/file-preview/src/components/markdown-editor.js +0 -535
- package/dist/ui/file-preview/src/markdown/block-merge.d.ts +0 -25
- package/dist/ui/file-preview/src/markdown/block-merge.js +0 -86
- package/dist/ui/file-preview/src/markdown/link-modal.d.ts +0 -13
- package/dist/ui/file-preview/src/markdown/link-modal.js +0 -213
- package/dist/ui/file-preview/src/markdown/raw-editor.d.ts +0 -8
- package/dist/ui/file-preview/src/markdown/raw-editor.js +0 -61
- package/dist/ui/file-preview/src/markdown/selection-toolbar.d.ts +0 -14
- package/dist/ui/file-preview/src/markdown/selection-toolbar.js +0 -128
- package/dist/ui/file-preview/src/markdown/toc.d.ts +0 -11
- package/dist/ui/file-preview/src/markdown/toc.js +0 -75
- package/dist/ui/file-preview/src/markdown-workspace/editor.d.ts +0 -36
- package/dist/ui/file-preview/src/markdown-workspace/editor.js +0 -643
- package/dist/ui/file-preview/src/markdown-workspace/linking.d.ts +0 -9
- package/dist/ui/file-preview/src/markdown-workspace/linking.js +0 -210
- package/dist/ui/file-preview/src/markdown-workspace/outline.d.ts +0 -7
- package/dist/ui/file-preview/src/markdown-workspace/outline.js +0 -40
- package/dist/ui/file-preview/src/markdown-workspace/preview.d.ts +0 -8
- package/dist/ui/file-preview/src/markdown-workspace/preview.js +0 -33
- package/dist/ui/file-preview/src/markdown-workspace/slugify.d.ts +0 -3
- package/dist/ui/file-preview/src/markdown-workspace/slugify.js +0 -31
- package/dist/ui/file-preview/src/markdown-workspace/toc.d.ts +0 -11
- package/dist/ui/file-preview/src/markdown-workspace/toc.js +0 -75
- package/dist/ui/file-preview/src/markdown-workspace/utils.d.ts +0 -1
- package/dist/ui/file-preview/src/markdown-workspace/utils.js +0 -15
- package/dist/ui/file-preview/src/markdown-workspace/workspace-controller.d.ts +0 -25
- package/dist/ui/file-preview/src/markdown-workspace/workspace-controller.js +0 -40
- package/dist/ui/file-preview/types.d.ts +0 -1
- package/dist/ui/file-preview/types.js +0 -1
- package/dist/ui/server-integration.d.ts +0 -13
- package/dist/ui/server-integration.js +0 -31
- package/dist/ui/shared/ToolHeader.d.ts +0 -9
- package/dist/ui/shared/ToolHeader.js +0 -29
- package/dist/ui/shared/app-bootstrap.d.ts +0 -9
- package/dist/ui/shared/app-bootstrap.js +0 -15
- package/dist/ui/shared/guards.d.ts +0 -1
- package/dist/ui/shared/guards.js +0 -3
- package/dist/ui/shared/host-lifecycle.d.ts +0 -17
- package/dist/ui/shared/host-lifecycle.js +0 -41
- package/dist/ui/shared/rpc-client.d.ts +0 -14
- package/dist/ui/shared/rpc-client.js +0 -72
- package/dist/ui/shared/theme-adaptation.d.ts +0 -10
- package/dist/ui/shared/theme-adaptation.js +0 -118
- package/dist/ui/shared/tool-header.d.ts +0 -9
- package/dist/ui/shared/tool-header.js +0 -25
- package/dist/utils/ui-call-context.d.ts +0 -8
- package/dist/utils/ui-call-context.js +0 -72
- /package/dist/ui/config-editor/{app.d.ts → src/app.d.ts} +0 -0
- /package/dist/ui/config-editor/src/{App.js → app.js} +0 -0
- /package/dist/ui/file-preview/src/{App.d.ts → app.d.ts} +0 -0
- /package/dist/ui/file-preview/src/{App.js → app.js} +0 -0
|
@@ -1,643 +0,0 @@
|
|
|
1
|
-
import { renderMarkdown } from '../components/markdown-renderer.js';
|
|
2
|
-
function renderFormattingButtons() {
|
|
3
|
-
return `
|
|
4
|
-
<button class="markdown-format-button" type="button" data-format="bold"><strong>B</strong></button>
|
|
5
|
-
<button class="markdown-format-button" type="button" data-format="italic"><em>I</em></button>
|
|
6
|
-
<button class="markdown-format-button" type="button" data-format="strike"><span style="text-decoration:line-through">S</span></button>
|
|
7
|
-
<span class="markdown-format-sep" aria-hidden="true"></span>
|
|
8
|
-
<label class="markdown-format-size" title="Block style" aria-label="Block style">
|
|
9
|
-
<select id="markdown-block-style">
|
|
10
|
-
<option value="p" selected>Normal</option>
|
|
11
|
-
<option value="h1">H1</option>
|
|
12
|
-
<option value="h2">H2</option>
|
|
13
|
-
<option value="h3">H3</option>
|
|
14
|
-
</select>
|
|
15
|
-
</label>
|
|
16
|
-
<span class="markdown-format-sep" aria-hidden="true"></span>
|
|
17
|
-
<button class="markdown-format-button" type="button" data-format="quote" title="Quote" aria-label="Quote">❝</button>
|
|
18
|
-
<button class="markdown-format-button" type="button" data-format="list" title="List" aria-label="List">•</button>
|
|
19
|
-
<button class="markdown-format-button" type="button" data-format="link" title="Link" aria-label="Link">🔗</button>
|
|
20
|
-
<button class="markdown-format-button" type="button" data-format="code" title="Code" aria-label="Code">‹›</button>
|
|
21
|
-
`;
|
|
22
|
-
}
|
|
23
|
-
function renderModeToggleIcon(view) {
|
|
24
|
-
if (view === 'raw') {
|
|
25
|
-
return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg>';
|
|
26
|
-
}
|
|
27
|
-
return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16"></path><path d="M4 12h10"></path><path d="M4 17h7"></path></svg>';
|
|
28
|
-
}
|
|
29
|
-
export function renderMarkdownCopyButton() {
|
|
30
|
-
return `<button class="markdown-editor-copy-button" type="button" id="copy-active-markdown" title="Copy" aria-label="Copy"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><span>Copy</span></button>`;
|
|
31
|
-
}
|
|
32
|
-
export function renderMarkdownModeToggle(view) {
|
|
33
|
-
return `
|
|
34
|
-
<div class="markdown-editor-mode-toggle" role="tablist" aria-label="Editor mode">
|
|
35
|
-
<div class="markdown-editor-mode-toggle-indicator markdown-editor-mode-toggle-indicator--${view}" aria-hidden="true"></div>
|
|
36
|
-
<button class="markdown-editor-mode-option${view === 'raw' ? ' is-active' : ''}" type="button" id="markdown-mode-raw" role="tab" aria-selected="${view === 'raw' ? 'true' : 'false'}" title="Raw" aria-label="Raw">${renderModeToggleIcon('raw')}<span>Raw</span></button>
|
|
37
|
-
<button class="markdown-editor-mode-option${view === 'markdown' ? ' is-active' : ''}" type="button" id="markdown-mode-markdown" role="tab" aria-selected="${view === 'markdown' ? 'true' : 'false'}" title="Preview" aria-label="Preview">${renderModeToggleIcon('markdown')}<span>Preview</span></button>
|
|
38
|
-
</div>
|
|
39
|
-
`;
|
|
40
|
-
}
|
|
41
|
-
export function renderMarkdownEditorShell(options) {
|
|
42
|
-
const isMarkdownView = options.view === 'markdown';
|
|
43
|
-
return `
|
|
44
|
-
<div class="markdown-editor-shell markdown-editor-shell--${options.view}">
|
|
45
|
-
<section class="markdown-editor-pane markdown-editor-pane--${options.view}" aria-label="Markdown editor">
|
|
46
|
-
${isMarkdownView ? `<div id="markdown-editor-context-menu" class="markdown-editor-context-menu" hidden>${renderFormattingButtons()}</div><div id="markdown-link-modal" class="markdown-link-modal" hidden><div class="markdown-link-modal-card"><div class="markdown-link-mode-tabs"><button type="button" id="markdown-link-mode-file" class="markdown-link-mode-tab is-active">File</button><button type="button" id="markdown-link-mode-url" class="markdown-link-mode-tab">URL</button></div><div id="markdown-link-file-fields"><label class="markdown-link-modal-label" for="markdown-link-search">Find note</label><input id="markdown-link-search" class="markdown-link-modal-input" type="text" placeholder="Search files..." /><div id="markdown-link-results" class="markdown-link-results"></div><label class="markdown-link-modal-label" for="markdown-link-heading">Heading</label><select id="markdown-link-heading" class="markdown-link-modal-input markdown-link-modal-select"><option value="">None</option></select><label class="markdown-link-modal-label" for="markdown-link-alias">Alias</label><input id="markdown-link-alias" class="markdown-link-modal-input" type="text" placeholder="Optional label" /></div><div id="markdown-link-url-fields" hidden><label class="markdown-link-modal-label" for="markdown-link-input">URL</label><input id="markdown-link-input" class="markdown-link-modal-input" type="url" placeholder="https://example.com" /><label class="markdown-link-modal-label" for="markdown-link-label">Label</label><input id="markdown-link-label" class="markdown-link-modal-input" type="text" placeholder="Optional label" /></div><div class="markdown-link-modal-actions"><button type="button" id="markdown-link-cancel" class="markdown-link-modal-button">Cancel</button><button type="button" id="markdown-link-apply" class="markdown-link-modal-button markdown-link-modal-button--primary">Insert</button></div></div></div>` : ''}
|
|
47
|
-
<div id="markdown-editor-root" class="markdown-editor-root"></div>
|
|
48
|
-
</section>
|
|
49
|
-
</div>
|
|
50
|
-
`;
|
|
51
|
-
}
|
|
52
|
-
function collapseWhitespace(value) {
|
|
53
|
-
return value.replace(/\s+/g, ' ').trim();
|
|
54
|
-
}
|
|
55
|
-
function serializeNode(node) {
|
|
56
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
57
|
-
return node.textContent ?? '';
|
|
58
|
-
}
|
|
59
|
-
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
60
|
-
return '';
|
|
61
|
-
}
|
|
62
|
-
const element = node;
|
|
63
|
-
const tag = element.tagName.toLowerCase();
|
|
64
|
-
const children = Array.from(element.childNodes).map(serializeNode).join('');
|
|
65
|
-
switch (tag) {
|
|
66
|
-
case 'strong':
|
|
67
|
-
case 'b':
|
|
68
|
-
return `**${children}**`;
|
|
69
|
-
case 'em':
|
|
70
|
-
case 'i':
|
|
71
|
-
return `*${children}*`;
|
|
72
|
-
case 'u':
|
|
73
|
-
return `<u>${children}</u>`;
|
|
74
|
-
case 's':
|
|
75
|
-
case 'strike':
|
|
76
|
-
return `~~${children}~~`;
|
|
77
|
-
case 'code':
|
|
78
|
-
return `\`${children}\``;
|
|
79
|
-
case 'a': {
|
|
80
|
-
const wikiLink = element.getAttribute('data-wiki-link');
|
|
81
|
-
if (wikiLink) {
|
|
82
|
-
return wikiLink;
|
|
83
|
-
}
|
|
84
|
-
const href = element.getAttribute('href') ?? 'https://example.com';
|
|
85
|
-
return `[${children || href}](${href})`;
|
|
86
|
-
}
|
|
87
|
-
case 'span': {
|
|
88
|
-
const color = element.style.color;
|
|
89
|
-
const fontSize = element.style.fontSize;
|
|
90
|
-
if (color || fontSize) {
|
|
91
|
-
const styleParts = [color ? `color:${color}` : '', fontSize ? `font-size:${fontSize}` : ''].filter(Boolean).join(';');
|
|
92
|
-
return `<span style="${styleParts}">${children}</span>`;
|
|
93
|
-
}
|
|
94
|
-
return children;
|
|
95
|
-
}
|
|
96
|
-
case 'font': {
|
|
97
|
-
const color = element.getAttribute('color');
|
|
98
|
-
const size = element.getAttribute('size');
|
|
99
|
-
const styleParts = [color ? `color:${color}` : '', size ? `font-size:${size}` : ''].filter(Boolean).join(';');
|
|
100
|
-
return styleParts ? `<span style="${styleParts}">${children}</span>` : children;
|
|
101
|
-
}
|
|
102
|
-
case 'br':
|
|
103
|
-
return '\n';
|
|
104
|
-
case 'p':
|
|
105
|
-
return `${children.trim()}\n\n`;
|
|
106
|
-
case 'h1':
|
|
107
|
-
return `# ${collapseWhitespace(children)}\n\n`;
|
|
108
|
-
case 'h2':
|
|
109
|
-
return `## ${collapseWhitespace(children)}\n\n`;
|
|
110
|
-
case 'h3':
|
|
111
|
-
return `### ${collapseWhitespace(children)}\n\n`;
|
|
112
|
-
case 'h4':
|
|
113
|
-
return `#### ${collapseWhitespace(children)}\n\n`;
|
|
114
|
-
case 'h5':
|
|
115
|
-
return `##### ${collapseWhitespace(children)}\n\n`;
|
|
116
|
-
case 'h6':
|
|
117
|
-
return `###### ${collapseWhitespace(children)}\n\n`;
|
|
118
|
-
case 'blockquote':
|
|
119
|
-
return `${children.trim().split('\n').map((line) => `> ${line}`).join('\n')}\n\n`;
|
|
120
|
-
case 'ul':
|
|
121
|
-
return `${Array.from(element.children).map((child) => `- ${collapseWhitespace(serializeNode(child))}`).join('\n')}\n\n`;
|
|
122
|
-
case 'ol':
|
|
123
|
-
return `${Array.from(element.children).map((child, index) => `${index + 1}. ${collapseWhitespace(serializeNode(child))}`).join('\n')}\n\n`;
|
|
124
|
-
case 'li':
|
|
125
|
-
return collapseWhitespace(children);
|
|
126
|
-
case 'div':
|
|
127
|
-
return `${children}${children.endsWith('\n') ? '' : '\n'}`;
|
|
128
|
-
default:
|
|
129
|
-
return children;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function htmlToMarkdown(html) {
|
|
133
|
-
const parser = new DOMParser();
|
|
134
|
-
const documentNode = parser.parseFromString(`<div>${html}</div>`, 'text/html');
|
|
135
|
-
const root = documentNode.body.firstElementChild;
|
|
136
|
-
if (!root) {
|
|
137
|
-
return '';
|
|
138
|
-
}
|
|
139
|
-
return Array.from(root.childNodes)
|
|
140
|
-
.map(serializeNode)
|
|
141
|
-
.join('')
|
|
142
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
143
|
-
.trim();
|
|
144
|
-
}
|
|
145
|
-
function applyRawTab(textarea) {
|
|
146
|
-
const start = textarea.selectionStart;
|
|
147
|
-
const end = textarea.selectionEnd;
|
|
148
|
-
const nextValue = `${textarea.value.slice(0, start)}\t${textarea.value.slice(end)}`;
|
|
149
|
-
textarea.value = nextValue;
|
|
150
|
-
textarea.selectionStart = start + 1;
|
|
151
|
-
textarea.selectionEnd = start + 1;
|
|
152
|
-
}
|
|
153
|
-
function replaceSelectionWithNode(node) {
|
|
154
|
-
const selection = window.getSelection();
|
|
155
|
-
if (!selection || selection.rangeCount === 0) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
const range = selection.getRangeAt(0);
|
|
159
|
-
range.deleteContents();
|
|
160
|
-
range.insertNode(node);
|
|
161
|
-
range.setStartAfter(node);
|
|
162
|
-
range.collapse(true);
|
|
163
|
-
selection.removeAllRanges();
|
|
164
|
-
selection.addRange(range);
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
function applyMarkdownFormat(format, value) {
|
|
168
|
-
switch (format) {
|
|
169
|
-
case 'bold':
|
|
170
|
-
document.execCommand('bold');
|
|
171
|
-
break;
|
|
172
|
-
case 'italic':
|
|
173
|
-
document.execCommand('italic');
|
|
174
|
-
break;
|
|
175
|
-
case 'strike':
|
|
176
|
-
document.execCommand('strikeThrough');
|
|
177
|
-
break;
|
|
178
|
-
case 'quote':
|
|
179
|
-
document.execCommand('formatBlock', false, 'blockquote');
|
|
180
|
-
break;
|
|
181
|
-
case 'list':
|
|
182
|
-
document.execCommand('insertUnorderedList');
|
|
183
|
-
break;
|
|
184
|
-
case 'link': {
|
|
185
|
-
if (value?.trim()) {
|
|
186
|
-
document.execCommand('createLink', false, value.trim());
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
case 'block-style':
|
|
191
|
-
if (value) {
|
|
192
|
-
document.execCommand('formatBlock', false, value);
|
|
193
|
-
}
|
|
194
|
-
break;
|
|
195
|
-
case 'code':
|
|
196
|
-
{
|
|
197
|
-
const code = document.createElement('code');
|
|
198
|
-
code.textContent = window.getSelection()?.toString() || 'code';
|
|
199
|
-
replaceSelectionWithNode(code);
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
default:
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
export function mountMarkdownEditor(options) {
|
|
207
|
-
const shell = options.target.closest('.markdown-editor-shell');
|
|
208
|
-
const contextMenu = shell?.querySelector('#markdown-editor-context-menu');
|
|
209
|
-
const formatButtons = shell ? Array.from(shell.querySelectorAll('[data-format]')) : [];
|
|
210
|
-
const blockStyleSelect = shell?.querySelector('#markdown-block-style');
|
|
211
|
-
const linkModal = shell?.querySelector('#markdown-link-modal');
|
|
212
|
-
const linkModeFile = shell?.querySelector('#markdown-link-mode-file');
|
|
213
|
-
const linkModeUrl = shell?.querySelector('#markdown-link-mode-url');
|
|
214
|
-
const linkFileFields = shell?.querySelector('#markdown-link-file-fields');
|
|
215
|
-
const linkUrlFields = shell?.querySelector('#markdown-link-url-fields');
|
|
216
|
-
const linkSearchInput = shell?.querySelector('#markdown-link-search');
|
|
217
|
-
const linkResults = shell?.querySelector('#markdown-link-results');
|
|
218
|
-
const linkHeadingSelect = shell?.querySelector('#markdown-link-heading');
|
|
219
|
-
const linkAliasInput = shell?.querySelector('#markdown-link-alias');
|
|
220
|
-
const linkInput = shell?.querySelector('#markdown-link-input');
|
|
221
|
-
const linkLabelInput = shell?.querySelector('#markdown-link-label');
|
|
222
|
-
const linkApply = shell?.querySelector('#markdown-link-apply');
|
|
223
|
-
const linkCancel = shell?.querySelector('#markdown-link-cancel');
|
|
224
|
-
let savedRange = null;
|
|
225
|
-
let linkMode = 'file';
|
|
226
|
-
let linkSearchResults = [];
|
|
227
|
-
let selectedLinkItem = null;
|
|
228
|
-
let linkResultsMessage = 'Search for a file to link';
|
|
229
|
-
let linkSearchRequestId = 0;
|
|
230
|
-
let linkHeadingRequestId = 0;
|
|
231
|
-
let lastMarkdownValue = options.value;
|
|
232
|
-
if (options.view === 'markdown') {
|
|
233
|
-
const editor = document.createElement('div');
|
|
234
|
-
editor.className = 'markdown-editor-surface markdown-editor-surface--markdown markdown markdown-doc';
|
|
235
|
-
editor.contentEditable = 'true';
|
|
236
|
-
editor.setAttribute('role', 'textbox');
|
|
237
|
-
editor.setAttribute('aria-multiline', 'true');
|
|
238
|
-
editor.innerHTML = renderMarkdown(options.value);
|
|
239
|
-
options.target.replaceChildren(editor);
|
|
240
|
-
const setLinkHeadingOptions = (headings = [], placeholder = 'None') => {
|
|
241
|
-
if (!linkHeadingSelect) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
linkHeadingSelect.replaceChildren();
|
|
245
|
-
const noneOption = document.createElement('option');
|
|
246
|
-
noneOption.value = '';
|
|
247
|
-
noneOption.textContent = placeholder;
|
|
248
|
-
linkHeadingSelect.appendChild(noneOption);
|
|
249
|
-
for (const heading of headings) {
|
|
250
|
-
const option = document.createElement('option');
|
|
251
|
-
option.value = heading.text;
|
|
252
|
-
option.textContent = heading.text;
|
|
253
|
-
linkHeadingSelect.appendChild(option);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
const loadHeadingsForItem = async (item) => {
|
|
257
|
-
if (!linkHeadingSelect) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const requestId = ++linkHeadingRequestId;
|
|
261
|
-
setLinkHeadingOptions([], 'Loading…');
|
|
262
|
-
try {
|
|
263
|
-
const headings = await options.loadHeadings?.(item.path) ?? [];
|
|
264
|
-
if (requestId !== linkHeadingRequestId || selectedLinkItem?.path !== item.path) {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
setLinkHeadingOptions(headings);
|
|
268
|
-
}
|
|
269
|
-
catch {
|
|
270
|
-
if (requestId !== linkHeadingRequestId || selectedLinkItem?.path !== item.path) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
setLinkHeadingOptions([], 'Failed to load headings');
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
const syncFromEditor = (syncContent) => {
|
|
277
|
-
if (syncContent) {
|
|
278
|
-
const nextMarkdownValue = htmlToMarkdown(editor.innerHTML);
|
|
279
|
-
if (nextMarkdownValue !== lastMarkdownValue) {
|
|
280
|
-
lastMarkdownValue = nextMarkdownValue;
|
|
281
|
-
options.onChange(nextMarkdownValue);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
if (contextMenu) {
|
|
285
|
-
const selection = window.getSelection();
|
|
286
|
-
const hasSelection = !!selection && !selection.isCollapsed && editor.contains(selection.anchorNode);
|
|
287
|
-
contextMenu.hidden = !hasSelection;
|
|
288
|
-
if (hasSelection && selection && selection.rangeCount > 0) {
|
|
289
|
-
const range = selection.getRangeAt(0);
|
|
290
|
-
savedRange = range.cloneRange();
|
|
291
|
-
const rect = range.getBoundingClientRect();
|
|
292
|
-
const shellRect = shell.getBoundingClientRect();
|
|
293
|
-
const left = Math.max(12, rect.left - shellRect.left + rect.width / 2 - contextMenu.offsetWidth / 2);
|
|
294
|
-
const top = Math.max(12, rect.top - shellRect.top - contextMenu.offsetHeight - 10);
|
|
295
|
-
contextMenu.style.left = `${left}px`;
|
|
296
|
-
contextMenu.style.top = `${top}px`;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
const restoreSelection = () => {
|
|
301
|
-
if (!savedRange) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
const selection = window.getSelection();
|
|
305
|
-
selection?.removeAllRanges();
|
|
306
|
-
selection?.addRange(savedRange);
|
|
307
|
-
};
|
|
308
|
-
const renderLinkResults = () => {
|
|
309
|
-
if (!linkResults) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
if (linkSearchResults.length === 0) {
|
|
313
|
-
const empty = document.createElement('div');
|
|
314
|
-
empty.className = 'markdown-link-results-empty';
|
|
315
|
-
empty.textContent = linkResultsMessage;
|
|
316
|
-
linkResults.replaceChildren(empty);
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
const fragment = document.createDocumentFragment();
|
|
320
|
-
for (const item of linkSearchResults) {
|
|
321
|
-
const button = document.createElement('button');
|
|
322
|
-
button.type = 'button';
|
|
323
|
-
button.className = `markdown-link-result${selectedLinkItem?.path === item.path ? ' is-active' : ''}`;
|
|
324
|
-
button.dataset.linkPath = item.path;
|
|
325
|
-
const title = document.createElement('span');
|
|
326
|
-
title.className = 'markdown-link-result-title';
|
|
327
|
-
title.textContent = item.title;
|
|
328
|
-
const path = document.createElement('span');
|
|
329
|
-
path.className = 'markdown-link-result-path';
|
|
330
|
-
path.textContent = item.relativePath;
|
|
331
|
-
button.append(title, path);
|
|
332
|
-
button.addEventListener('click', () => {
|
|
333
|
-
selectedLinkItem = item;
|
|
334
|
-
renderLinkResults();
|
|
335
|
-
void loadHeadingsForItem(item);
|
|
336
|
-
});
|
|
337
|
-
fragment.appendChild(button);
|
|
338
|
-
}
|
|
339
|
-
linkResults.replaceChildren(fragment);
|
|
340
|
-
};
|
|
341
|
-
const updateLinkMode = (mode) => {
|
|
342
|
-
linkMode = mode;
|
|
343
|
-
linkModeFile?.classList.toggle('is-active', mode === 'file');
|
|
344
|
-
linkModeUrl?.classList.toggle('is-active', mode === 'url');
|
|
345
|
-
if (linkFileFields) {
|
|
346
|
-
linkFileFields.hidden = mode !== 'file';
|
|
347
|
-
}
|
|
348
|
-
if (linkUrlFields) {
|
|
349
|
-
linkUrlFields.hidden = mode !== 'url';
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
const runLinkSearch = async () => {
|
|
353
|
-
if (!linkSearchInput || !options.searchLinks) {
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
const query = linkSearchInput.value.trim();
|
|
357
|
-
if (query.length === 0) {
|
|
358
|
-
linkSearchRequestId += 1;
|
|
359
|
-
linkSearchResults = [];
|
|
360
|
-
selectedLinkItem = null;
|
|
361
|
-
linkResultsMessage = 'Search for a file to link';
|
|
362
|
-
setLinkHeadingOptions();
|
|
363
|
-
renderLinkResults();
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
const requestId = ++linkSearchRequestId;
|
|
367
|
-
try {
|
|
368
|
-
const results = await options.searchLinks(query);
|
|
369
|
-
if (requestId !== linkSearchRequestId || query !== linkSearchInput.value.trim()) {
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
linkSearchResults = results;
|
|
373
|
-
selectedLinkItem = results[0] ?? null;
|
|
374
|
-
linkResultsMessage = results.length === 0 ? 'No matching files found' : 'Search for a file to link';
|
|
375
|
-
renderLinkResults();
|
|
376
|
-
if (selectedLinkItem) {
|
|
377
|
-
void loadHeadingsForItem(selectedLinkItem);
|
|
378
|
-
}
|
|
379
|
-
else {
|
|
380
|
-
setLinkHeadingOptions();
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
catch {
|
|
384
|
-
if (requestId !== linkSearchRequestId) {
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
linkSearchResults = [];
|
|
388
|
-
selectedLinkItem = null;
|
|
389
|
-
linkResultsMessage = 'Search failed. Try again.';
|
|
390
|
-
setLinkHeadingOptions();
|
|
391
|
-
renderLinkResults();
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
const handleInput = () => {
|
|
395
|
-
syncFromEditor(true);
|
|
396
|
-
};
|
|
397
|
-
const handleKeyDown = (event) => {
|
|
398
|
-
if (event.key === 'Tab') {
|
|
399
|
-
event.preventDefault();
|
|
400
|
-
document.execCommand('insertText', false, ' ');
|
|
401
|
-
syncFromEditor(true);
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
const handleSelectionChange = () => {
|
|
405
|
-
syncFromEditor(false);
|
|
406
|
-
};
|
|
407
|
-
const handleFocusOut = (event) => {
|
|
408
|
-
const nextTarget = event.relatedTarget;
|
|
409
|
-
const widgetShell = shell?.closest('.tool-shell');
|
|
410
|
-
if (nextTarget && (shell?.contains(nextTarget) || widgetShell?.contains(nextTarget))) {
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
if (contextMenu) {
|
|
414
|
-
contextMenu.hidden = true;
|
|
415
|
-
}
|
|
416
|
-
options.onBlur?.();
|
|
417
|
-
};
|
|
418
|
-
const handleFormatClick = (event) => {
|
|
419
|
-
const target = event.currentTarget;
|
|
420
|
-
const format = target.dataset.format;
|
|
421
|
-
if (!format) {
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
editor.focus();
|
|
425
|
-
restoreSelection();
|
|
426
|
-
if (format === 'link') {
|
|
427
|
-
const selectedText = window.getSelection()?.toString().trim() ?? '';
|
|
428
|
-
linkModal?.removeAttribute('hidden');
|
|
429
|
-
updateLinkMode('file');
|
|
430
|
-
if (linkAliasInput) {
|
|
431
|
-
linkAliasInput.value = selectedText;
|
|
432
|
-
}
|
|
433
|
-
if (linkLabelInput) {
|
|
434
|
-
linkLabelInput.value = selectedText;
|
|
435
|
-
}
|
|
436
|
-
if (linkSearchInput) {
|
|
437
|
-
linkSearchInput.value = '';
|
|
438
|
-
linkSearchInput.focus();
|
|
439
|
-
}
|
|
440
|
-
linkSearchResults = [];
|
|
441
|
-
selectedLinkItem = null;
|
|
442
|
-
linkResultsMessage = 'Search for a file to link';
|
|
443
|
-
setLinkHeadingOptions();
|
|
444
|
-
renderLinkResults();
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
applyMarkdownFormat(format);
|
|
448
|
-
syncFromEditor(true);
|
|
449
|
-
};
|
|
450
|
-
const handleBlockStyleChange = () => {
|
|
451
|
-
if (!blockStyleSelect?.value) {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
editor.focus();
|
|
455
|
-
restoreSelection();
|
|
456
|
-
applyMarkdownFormat('block-style', blockStyleSelect.value);
|
|
457
|
-
syncFromEditor(true);
|
|
458
|
-
};
|
|
459
|
-
const closeLinkModal = () => {
|
|
460
|
-
linkModal?.setAttribute('hidden', '');
|
|
461
|
-
if (linkInput) {
|
|
462
|
-
linkInput.value = '';
|
|
463
|
-
}
|
|
464
|
-
if (linkLabelInput) {
|
|
465
|
-
linkLabelInput.value = '';
|
|
466
|
-
}
|
|
467
|
-
if (linkAliasInput) {
|
|
468
|
-
linkAliasInput.value = '';
|
|
469
|
-
}
|
|
470
|
-
if (linkSearchInput) {
|
|
471
|
-
linkSearchInput.value = '';
|
|
472
|
-
}
|
|
473
|
-
setLinkHeadingOptions();
|
|
474
|
-
linkSearchResults = [];
|
|
475
|
-
selectedLinkItem = null;
|
|
476
|
-
linkResultsMessage = 'Search for a file to link';
|
|
477
|
-
renderLinkResults();
|
|
478
|
-
};
|
|
479
|
-
const handleLinkApply = () => {
|
|
480
|
-
editor.focus();
|
|
481
|
-
restoreSelection();
|
|
482
|
-
if (linkMode === 'url') {
|
|
483
|
-
const href = linkInput?.value?.trim();
|
|
484
|
-
const label = linkLabelInput?.value?.trim() || window.getSelection()?.toString().trim() || href || 'link';
|
|
485
|
-
if (href) {
|
|
486
|
-
const anchor = document.createElement('a');
|
|
487
|
-
anchor.setAttribute('href', href);
|
|
488
|
-
anchor.textContent = label;
|
|
489
|
-
if (replaceSelectionWithNode(anchor)) {
|
|
490
|
-
syncFromEditor(true);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
else if (selectedLinkItem) {
|
|
495
|
-
const selectedHeading = linkHeadingSelect?.value?.trim();
|
|
496
|
-
const alias = linkAliasInput?.value?.trim();
|
|
497
|
-
const pathPart = selectedLinkItem.path === options.currentFilePath ? '' : selectedLinkItem.wikiPath;
|
|
498
|
-
const wikiLink = `[[${pathPart}${selectedHeading ? `#${selectedHeading}` : ''}${alias ? `|${alias}` : ''}]]`;
|
|
499
|
-
const href = `${selectedLinkItem.relativePath}${selectedHeading ? `#${selectedHeading}` : ''}`;
|
|
500
|
-
const label = alias || selectedHeading || selectedLinkItem.title;
|
|
501
|
-
const anchor = document.createElement('a');
|
|
502
|
-
anchor.setAttribute('href', href);
|
|
503
|
-
anchor.dataset.wikiLink = wikiLink;
|
|
504
|
-
anchor.textContent = label;
|
|
505
|
-
if (replaceSelectionWithNode(anchor)) {
|
|
506
|
-
syncFromEditor(true);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
closeLinkModal();
|
|
510
|
-
};
|
|
511
|
-
editor.addEventListener('input', handleInput);
|
|
512
|
-
editor.addEventListener('keydown', handleKeyDown);
|
|
513
|
-
editor.addEventListener('focusout', handleFocusOut);
|
|
514
|
-
document.addEventListener('selectionchange', handleSelectionChange);
|
|
515
|
-
formatButtons.forEach((button) => button.addEventListener('click', handleFormatClick));
|
|
516
|
-
blockStyleSelect?.addEventListener('change', handleBlockStyleChange);
|
|
517
|
-
linkModeFile?.addEventListener('click', () => updateLinkMode('file'));
|
|
518
|
-
linkModeUrl?.addEventListener('click', () => {
|
|
519
|
-
updateLinkMode('url');
|
|
520
|
-
linkInput?.focus();
|
|
521
|
-
});
|
|
522
|
-
const handleSearchInput = () => { void runLinkSearch(); };
|
|
523
|
-
linkSearchInput?.addEventListener('input', handleSearchInput);
|
|
524
|
-
linkApply?.addEventListener('click', handleLinkApply);
|
|
525
|
-
linkCancel?.addEventListener('click', closeLinkModal);
|
|
526
|
-
syncFromEditor(false);
|
|
527
|
-
renderLinkResults();
|
|
528
|
-
if (typeof options.initialScrollTop === 'number') {
|
|
529
|
-
editor.scrollTop = options.initialScrollTop;
|
|
530
|
-
}
|
|
531
|
-
return {
|
|
532
|
-
destroy: () => {
|
|
533
|
-
editor.removeEventListener('input', handleInput);
|
|
534
|
-
editor.removeEventListener('keydown', handleKeyDown);
|
|
535
|
-
editor.removeEventListener('focusout', handleFocusOut);
|
|
536
|
-
document.removeEventListener('selectionchange', handleSelectionChange);
|
|
537
|
-
formatButtons.forEach((button) => button.removeEventListener('click', handleFormatClick));
|
|
538
|
-
blockStyleSelect?.removeEventListener('change', handleBlockStyleChange);
|
|
539
|
-
linkSearchInput?.removeEventListener('input', handleSearchInput);
|
|
540
|
-
linkApply?.removeEventListener('click', handleLinkApply);
|
|
541
|
-
linkCancel?.removeEventListener('click', closeLinkModal);
|
|
542
|
-
options.target.replaceChildren();
|
|
543
|
-
},
|
|
544
|
-
focus: () => {
|
|
545
|
-
editor.focus();
|
|
546
|
-
},
|
|
547
|
-
getValue: () => htmlToMarkdown(editor.innerHTML),
|
|
548
|
-
setValue: (value) => {
|
|
549
|
-
lastMarkdownValue = value;
|
|
550
|
-
editor.innerHTML = renderMarkdown(value);
|
|
551
|
-
syncFromEditor(false);
|
|
552
|
-
},
|
|
553
|
-
revealLine: (_lineNumber, headingId) => {
|
|
554
|
-
if (headingId) {
|
|
555
|
-
const heading = editor.querySelector(`#${CSS.escape(headingId)}`);
|
|
556
|
-
if (heading) {
|
|
557
|
-
heading.scrollIntoView({ block: 'start', inline: 'nearest' });
|
|
558
|
-
editor.scrollTop = Math.max(editor.scrollTop - 24, 0);
|
|
559
|
-
heading.setAttribute('tabindex', '-1');
|
|
560
|
-
heading.focus({ preventScroll: true });
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
editor.focus();
|
|
565
|
-
},
|
|
566
|
-
setScrollTop: (scrollTop) => {
|
|
567
|
-
editor.scrollTop = Math.max(0, scrollTop);
|
|
568
|
-
},
|
|
569
|
-
};
|
|
570
|
-
}
|
|
571
|
-
const textarea = document.createElement('textarea');
|
|
572
|
-
textarea.className = 'markdown-editor-textarea markdown-editor-textarea--raw';
|
|
573
|
-
textarea.spellcheck = false;
|
|
574
|
-
textarea.setAttribute('autocomplete', 'off');
|
|
575
|
-
textarea.setAttribute('autocorrect', 'off');
|
|
576
|
-
textarea.setAttribute('autocapitalize', 'off');
|
|
577
|
-
textarea.placeholder = 'Edit raw markdown...';
|
|
578
|
-
textarea.value = options.value;
|
|
579
|
-
options.target.replaceChildren(textarea);
|
|
580
|
-
const autosize = () => {
|
|
581
|
-
textarea.style.height = 'auto';
|
|
582
|
-
textarea.style.height = `${Math.max(textarea.scrollHeight, 640)}px`;
|
|
583
|
-
};
|
|
584
|
-
const handleInput = () => {
|
|
585
|
-
autosize();
|
|
586
|
-
options.onChange(textarea.value);
|
|
587
|
-
};
|
|
588
|
-
const handleFocusOut = (event) => {
|
|
589
|
-
const nextTarget = event.relatedTarget;
|
|
590
|
-
const widgetShell = shell?.closest('.tool-shell');
|
|
591
|
-
if (nextTarget && (shell?.contains(nextTarget) || widgetShell?.contains(nextTarget))) {
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
|
-
options.onBlur?.();
|
|
595
|
-
};
|
|
596
|
-
const handleKeyDown = (event) => {
|
|
597
|
-
if (event.key !== 'Tab') {
|
|
598
|
-
return;
|
|
599
|
-
}
|
|
600
|
-
event.preventDefault();
|
|
601
|
-
applyRawTab(textarea);
|
|
602
|
-
autosize();
|
|
603
|
-
options.onChange(textarea.value);
|
|
604
|
-
};
|
|
605
|
-
textarea.addEventListener('input', handleInput);
|
|
606
|
-
textarea.addEventListener('keydown', handleKeyDown);
|
|
607
|
-
textarea.addEventListener('focusout', handleFocusOut);
|
|
608
|
-
autosize();
|
|
609
|
-
if (typeof options.initialScrollTop === 'number') {
|
|
610
|
-
textarea.scrollTop = options.initialScrollTop;
|
|
611
|
-
}
|
|
612
|
-
return {
|
|
613
|
-
destroy: () => {
|
|
614
|
-
textarea.removeEventListener('input', handleInput);
|
|
615
|
-
textarea.removeEventListener('keydown', handleKeyDown);
|
|
616
|
-
textarea.removeEventListener('focusout', handleFocusOut);
|
|
617
|
-
options.target.replaceChildren();
|
|
618
|
-
},
|
|
619
|
-
focus: () => {
|
|
620
|
-
textarea.focus();
|
|
621
|
-
},
|
|
622
|
-
getValue: () => textarea.value,
|
|
623
|
-
setValue: (value) => {
|
|
624
|
-
textarea.value = value;
|
|
625
|
-
autosize();
|
|
626
|
-
},
|
|
627
|
-
revealLine: (lineNumber) => {
|
|
628
|
-
const targetLine = Math.max(1, Math.floor(lineNumber));
|
|
629
|
-
const lines = textarea.value.split('\n');
|
|
630
|
-
let index = 0;
|
|
631
|
-
for (let currentLine = 1; currentLine < targetLine && currentLine <= lines.length; currentLine += 1) {
|
|
632
|
-
index += lines[currentLine - 1].length + 1;
|
|
633
|
-
}
|
|
634
|
-
textarea.focus();
|
|
635
|
-
textarea.setSelectionRange(index, index);
|
|
636
|
-
const lineHeight = Number.parseFloat(window.getComputedStyle(textarea).lineHeight || '20') || 20;
|
|
637
|
-
textarea.scrollTop = Math.max(0, (targetLine - 1) * lineHeight - lineHeight * 2);
|
|
638
|
-
},
|
|
639
|
-
setScrollTop: (scrollTop) => {
|
|
640
|
-
textarea.scrollTop = Math.max(0, scrollTop);
|
|
641
|
-
},
|
|
642
|
-
};
|
|
643
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface ResolvedMarkdownLink {
|
|
2
|
-
kind: 'external' | 'anchor' | 'file';
|
|
3
|
-
href: string;
|
|
4
|
-
url?: string;
|
|
5
|
-
targetPath?: string;
|
|
6
|
-
anchor?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function rewriteWikiLinks(source: string): string;
|
|
9
|
-
export declare function resolveMarkdownLink(currentPath: string, rawHref: string): ResolvedMarkdownLink;
|