OXYGENHUB
# df5c69cbd047 oxygenhub / web / editor / editor.js
2.4 KiB · JavaScript · last changed Web edits and browser conflict resolution; landing under a policy 1 month ago source blame history raw
1
// The hub's file editor (hub spec §6.9): CodeMirror 6 mounted over a
2
// textarea, which stays the form field, so the page works without script.
3
import { EditorView, basicSetup } from "codemirror";
4
import { EditorState } from "@codemirror/state";
5
import { keymap } from "@codemirror/view";
6
import { indentWithTab } from "@codemirror/commands";
7
import { javascript } from "@codemirror/lang-javascript";
8
import { rust } from "@codemirror/lang-rust";
9
import { cpp } from "@codemirror/lang-cpp";
10
import { python } from "@codemirror/lang-python";
11
import { markdown } from "@codemirror/lang-markdown";
12
import { html } from "@codemirror/lang-html";
13
import { css } from "@codemirror/lang-css";
14
import { json } from "@codemirror/lang-json";
15
import { yaml } from "@codemirror/lang-yaml";
16
import { oneDark } from "@codemirror/theme-one-dark";
17
18
function language(path) {
19
  const ext = (path.split(".").pop() || "").toLowerCase();
20
  switch (ext) {
21
    case "js": case "mjs": case "cjs": return javascript();
22
    case "ts": case "mts": return javascript({ typescript: true });
23
    case "jsx": return javascript({ jsx: true });
24
    case "tsx": return javascript({ jsx: true, typescript: true });
25
    case "rs": return rust();
26
    case "c": case "h": case "cc": case "cpp": case "hpp": case "cxx": return cpp();
27
    case "py": return python();
28
    case "md": case "markdown": return markdown();
29
    case "html": case "htm": return html();
30
    case "css": return css();
31
    case "json": return json();
32
    case "yml": case "yaml": return yaml();
33
    default: return [];
34
  }
35
}
36
37
function dark() {
38
  const t = document.documentElement.dataset.theme;
39
  if (t === "light") return false;
40
  if (t === "dark") return true;
41
  return !window.matchMedia || !window.matchMedia("(prefers-color-scheme: light)").matches;
42
}
43
44
function mount(textarea) {
45
  const view = new EditorView({
46
    state: EditorState.create({
47
      doc: textarea.value,
48
      extensions: [basicSetup, keymap.of([indentWithTab]), language(textarea.dataset.path || ""), dark() ? oneDark : [], EditorView.lineWrapping],
49
    }),
50
  });
51
  textarea.style.display = "none";
52
  textarea.parentNode.insertBefore(view.dom, textarea);
53
  view.dom.classList.add("cm-host");
54
  const form = textarea.form;
55
  if (form) {
56
    form.addEventListener("submit", () => {
57
      textarea.value = view.state.doc.toString();
58
    });
59
  }
60
  return view;
61
}
62
63
document.querySelectorAll("textarea.code").forEach(mount);
64
window.OxyEditor = { mount };