diff options
Diffstat (limited to 'src/editor.mjs')
-rw-r--r-- | src/editor.mjs | 73 |
1 files changed, 23 insertions, 50 deletions
diff --git a/src/editor.mjs b/src/editor.mjs index 9ff8be6..92513a3 100644 --- a/src/editor.mjs +++ b/src/editor.mjs | |||
@@ -1,8 +1,8 @@ | |||
1 | /*global EasyMDE*/ | 1 | /*global EasyMDE*/ |
2 | /*eslint no-undef: "error"*/ | 2 | /*eslint no-undef: "error"*/ |
3 | import { markdown2HTML, generateMaps } from './dumbymap' | 3 | import { markdown2HTML, generateMaps, createDocLinks } from './dumbymap' |
4 | import { defaultAliases, parseConfigsFromYaml } from 'mapclay' | 4 | import { defaultAliases, parseConfigsFromYaml } from 'mapclay' |
5 | import { createDocLinks } from './dumbymap.mjs' | 5 | import { Suggestion } from './MenuItem' |
6 | 6 | ||
7 | // Set up Containers {{{ | 7 | // Set up Containers {{{ |
8 | 8 | ||
@@ -214,18 +214,13 @@ window.onhashchange = () => { | |||
214 | // }}} | 214 | // }}} |
215 | // Completion in Code Blok {{{ | 215 | // Completion in Code Blok {{{ |
216 | // Elements about suggestions {{{ | 216 | // Elements about suggestions {{{ |
217 | const suggestionsEle = document.createElement('div') | 217 | const menu = document.createElement('div') |
218 | suggestionsEle.classList.add('container__suggestions'); | 218 | menu.id = 'menu' |
219 | document.body.append(suggestionsEle) | 219 | menu.onclick = () => menu.style.display = 'none' |
220 | document.body.append(menu) | ||
220 | 221 | ||
221 | const rendererOptions = {} | 222 | const rendererOptions = {} |
222 | 223 | ||
223 | class Suggestion { | ||
224 | constructor({ text, replace }) { | ||
225 | this.text = text | ||
226 | this.replace = replace | ||
227 | } | ||
228 | } | ||
229 | // }}} | 224 | // }}} |
230 | // Aliases for map options {{{ | 225 | // Aliases for map options {{{ |
231 | const aliasesForMapOptions = {} | 226 | const aliasesForMapOptions = {} |
@@ -460,51 +455,29 @@ const getSuggestions = (anchor) => { | |||
460 | const addSuggestions = (anchor, suggestions) => { | 455 | const addSuggestions = (anchor, suggestions) => { |
461 | 456 | ||
462 | if (suggestions.length === 0) { | 457 | if (suggestions.length === 0) { |
463 | suggestionsEle.style.display = 'none'; | 458 | menu.style.display = 'none'; |
464 | return | 459 | return |
465 | } else { | 460 | } else { |
466 | suggestionsEle.style.display = 'block'; | 461 | menu.style.display = 'block'; |
467 | } | 462 | } |
468 | 463 | ||
469 | suggestionsEle.innerHTML = '' | 464 | menu.innerHTML = '' |
470 | suggestions.forEach((suggestion) => { | 465 | suggestions |
471 | const option = document.createElement('div'); | 466 | .map(s => s.createElement(cm)) |
472 | if (suggestion.text.startsWith('<')) { | 467 | .forEach(option => menu.appendChild(option)) |
473 | option.innerHTML = suggestion.text; | ||
474 | } else { | ||
475 | option.innerText = suggestion.text; | ||
476 | } | ||
477 | option.classList.add('container__suggestion'); | ||
478 | option.onmouseover = () => { | ||
479 | Array.from(suggestionsEle.children).forEach(s => s.classList.remove('focus')) | ||
480 | option.classList.add('focus') | ||
481 | } | ||
482 | option.onmouseout = () => { | ||
483 | option.classList.remove('focus') | ||
484 | } | ||
485 | option.onclick = () => { | ||
486 | cm.setSelection(anchor, { ...anchor, ch: 0 }) | ||
487 | cm.replaceSelection(suggestion.replace) | ||
488 | cm.focus(); | ||
489 | const newAnchor = { ...anchor, ch: suggestion.replace.length } | ||
490 | cm.setCursor(newAnchor); | ||
491 | }; | ||
492 | suggestionsEle.appendChild(option); | ||
493 | }); | ||
494 | 468 | ||
495 | const widgetAnchor = document.createElement('div') | 469 | const widgetAnchor = document.createElement('div') |
496 | cm.addWidget(anchor, widgetAnchor, true) | 470 | cm.addWidget(anchor, widgetAnchor, true) |
497 | const rect = widgetAnchor.getBoundingClientRect() | 471 | const rect = widgetAnchor.getBoundingClientRect() |
498 | suggestionsEle.style.left = `calc(${rect.left}px + 2rem)`; | 472 | menu.style.left = `calc(${rect.left}px + 2rem)`; |
499 | suggestionsEle.style.top = `calc(${rect.bottom}px + 1rem)`; | 473 | menu.style.top = `calc(${rect.bottom}px + 1rem)`; |
500 | suggestionsEle.style.maxWidth = `calc(${window.innerWidth}px - ${rect.x}px - 3rem)`; | 474 | menu.style.maxWidth = `calc(${window.innerWidth}px - ${rect.x}px - 3rem)`; |
501 | suggestionsEle.style.display = 'block' | 475 | menu.style.display = 'block' |
502 | } | 476 | } |
503 | // }}} | 477 | // }}} |
504 | // EVENT: Suggests for current selection {{{ | 478 | // EVENT: Suggests for current selection {{{ |
505 | // FIXME Dont show suggestion when selecting multiple chars | 479 | // FIXME Dont show suggestion when selecting multiple chars |
506 | cm.on("cursorActivity", (_) => { | 480 | cm.on("cursorActivity", (_) => { |
507 | suggestionsEle.style.display = 'none' | ||
508 | const anchor = cm.getCursor() | 481 | const anchor = cm.getCursor() |
509 | 482 | ||
510 | if (insideCodeblockForMap(anchor)) { | 483 | if (insideCodeblockForMap(anchor)) { |
@@ -512,7 +485,7 @@ cm.on("cursorActivity", (_) => { | |||
512 | } | 485 | } |
513 | }); | 486 | }); |
514 | cm.on("blur", () => { | 487 | cm.on("blur", () => { |
515 | suggestionsEle.style.display = 'none' | 488 | menu.style.display = 'none' |
516 | cm.getWrapperElement().classList.remove('focus') | 489 | cm.getWrapperElement().classList.remove('focus') |
517 | HtmlContainer.classList.add('focus') | 490 | HtmlContainer.classList.add('focus') |
518 | }) | 491 | }) |
@@ -520,25 +493,25 @@ cm.on("blur", () => { | |||
520 | // EVENT: keydown for suggestions {{{ | 493 | // EVENT: keydown for suggestions {{{ |
521 | const keyForSuggestions = ['Tab', 'Enter', 'Escape'] | 494 | const keyForSuggestions = ['Tab', 'Enter', 'Escape'] |
522 | cm.on('keydown', (_, e) => { | 495 | cm.on('keydown', (_, e) => { |
523 | if (!cm.hasFocus || !keyForSuggestions.includes(e.key) || suggestionsEle.style.display === 'none') return; | 496 | if (!cm.hasFocus || !keyForSuggestions.includes(e.key) || menu.style.display === 'none') return; |
524 | 497 | ||
525 | // Directly add a newline when no suggestion is selected | 498 | // Directly add a newline when no suggestion is selected |
526 | const currentSuggestion = suggestionsEle.querySelector('.container__suggestion.focus') | 499 | const currentSuggestion = menu.querySelector('.container__suggestion.focus') |
527 | if (!currentSuggestion && e.key === 'Enter') return | 500 | if (!currentSuggestion && e.key === 'Enter') return |
528 | 501 | ||
529 | // Override default behavior | 502 | // Override default behavior |
530 | e.preventDefault(); | 503 | e.preventDefault(); |
531 | 504 | ||
532 | // Suggestion when pressing Tab or Shift + Tab | 505 | // Suggestion when pressing Tab or Shift + Tab |
533 | const nextSuggestion = currentSuggestion?.nextSibling ?? suggestionsEle.querySelector('.container__suggestion:first-child') | 506 | const nextSuggestion = currentSuggestion?.nextSibling ?? menu.querySelector('.container__suggestion:first-child') |
534 | const previousSuggestion = currentSuggestion?.previousSibling ?? suggestionsEle.querySelector('.container__suggestion:last-child') | 507 | const previousSuggestion = currentSuggestion?.previousSibling ?? menu.querySelector('.container__suggestion:last-child') |
535 | const focusSuggestion = e.shiftKey ? previousSuggestion : nextSuggestion | 508 | const focusSuggestion = e.shiftKey ? previousSuggestion : nextSuggestion |
536 | 509 | ||
537 | // Current editor selection state | 510 | // Current editor selection state |
538 | const anchor = cm.getCursor() | 511 | const anchor = cm.getCursor() |
539 | switch (e.key) { | 512 | switch (e.key) { |
540 | case 'Tab': | 513 | case 'Tab': |
541 | Array.from(suggestionsEle.children).forEach(s => s.classList.remove('focus')) | 514 | Array.from(menu.children).forEach(s => s.classList.remove('focus')) |
542 | focusSuggestion.classList.add('focus') | 515 | focusSuggestion.classList.add('focus') |
543 | focusSuggestion.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) | 516 | focusSuggestion.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) |
544 | break; | 517 | break; |
@@ -546,7 +519,7 @@ cm.on('keydown', (_, e) => { | |||
546 | currentSuggestion.onclick() | 519 | currentSuggestion.onclick() |
547 | break; | 520 | break; |
548 | case 'Escape': | 521 | case 'Escape': |
549 | suggestionsEle.style.display = 'none'; | 522 | menu.style.display = 'none'; |
550 | // Focus editor again | 523 | // Focus editor again |
551 | setTimeout(() => cm.focus() && cm.setCursor(anchor), 100) | 524 | setTimeout(() => cm.focus() && cm.setCursor(anchor), 100) |
552 | break; | 525 | break; |