From 4f17bc1431ead015cd14d7646dd5356c589d6d1d Mon Sep 17 00:00:00 2001 From: Hsieh Chin Fan Date: Tue, 8 Oct 2024 00:59:37 +0800 Subject: feat: sync selection from HTML to CodeMirror This is for adding reference style links --- src/editor.mjs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/editor.mjs b/src/editor.mjs index d1f84a2..533ff16 100644 --- a/src/editor.mjs +++ b/src/editor.mjs @@ -404,6 +404,13 @@ const completeForCodeBlock = change => { * @param {HTMLElement} menu -- menu of dumbymap */ const menuForEditor = (event, menu) => { + event.preventDefault() + + if (cm.getSelection() && refLinks.length > 0) { + menu.replaceChildren() + menu.appendChild(menuItem.addRefLink(cm, refLinks)) + } + if (context.dataset.mode !== 'editing') { const switchToEditingMode = new menuItem.Item({ innerHTML: 'EDIT', @@ -439,7 +446,7 @@ const menuForEditor = (event, menu) => { { line: Infinity } ) refLinks = getRefLinks() - map.renderer.addMarker({xy: [Number(x), Number(y)], title: `${map.id}@${x},${y}`, type: 'circle'}) + map.renderer.addMarker({ xy: [Number(x), Number(y)], title: `${map.id}@${x},${y}`, type: 'circle' }) } }) menu.insertBefore(item, menu.firstChild) @@ -1001,4 +1008,52 @@ cm.getWrapperElement().oncontextmenu = e => { } } +/** HACK Sync selection from HTML to CodeMirror */ +document.addEventListener("selectionchange", () => { + if (cm.hasFocus()) { + return + } + + const selection = document.getSelection() + if (selection.type === 'Range') { + const content = selection.getRangeAt(0).toString() + const parentWithSourceLine = selection.anchorNode.parentElement.closest('.source-line') + const lineStart = Number(parentWithSourceLine?.dataset?.sourceLine ?? NaN) + const lineEnd = Number(parentWithSourceLine?.nextSibling?.dataset?.sourceLine ?? NaN) + // TODO Also return when range contains anchor element + if (content.includes('\n') || isNaN(lineStart)) { + cm.setSelection(cm.getCursor()) + return + } + + let texts = [content] + let sibling = selection.anchorNode.previousSibling + while (sibling) { + texts.push(sibling.textContent) + sibling = sibling.previousSibling + } + + const anchor = { line: lineStart, ch: 0 } + + texts + .filter(t => t && t !== '\n') + .map(t => t.replace('\n', '')) + .reverse() + .forEach(text => { + let index = cm.getLine(anchor.line).indexOf(text, anchor.ch) + while (index === -1) { + anchor.line += 1 + anchor.ch = 0 + if (anchor.line >= lineEnd) { + cm.setSelection(cm.setCursor()) + return + } + index = cm.getLine(anchor.line).indexOf(text) + } + anchor.ch = index + text.length + }) + + cm.setSelection({ ...anchor, ch: anchor.ch - content.length }, anchor) + } +}); // vim: sw=2 ts=2 foldmethod=marker foldmarker={{{,}}} -- cgit v1.2.3-70-g09d2