on-codemerge
Version:
A WYSIWYG editor for on-codemerge is a user-friendly interface that allows users to edit and view their code in real time, exactly as it will appear in the final product
90 lines (89 loc) • 3.88 kB
JavaScript
/*! on-codemerge v1.3.1 @author Pavel Kuzmin @license MIT @homepage https://s00d.github.io/on-codemerge/ @repository git+https://github.com/s00d/on-codemerge.git Copyright (c) 2026 Pavel Kuzmin - Built on 2026-07-02T13:39:17.947Z */
var p = Object.defineProperty;
var h = (i, t, e) => t in i ? p(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
var o = (i, t, e) => h(i, typeof t != "symbol" ? t + "" : t, e);
import d from "../../icons/mentions.svg.mjs";
import { createToolbarButton as c } from "../ToolbarPlugin/utils.mjs";
import { PopupManager as m } from "../../core/ui/PopupManager.mjs";
class b {
constructor() {
o(this, "name", "mentions");
o(this, "editor", null);
o(this, "popup", null);
// query is handled by MentionsMenu
o(this, "savedCursor", null);
o(this, "toolbarButton", null);
o(this, "onInput", (t) => {
var u, l;
if (!this.editor) return;
const e = (u = this.editor.getTextFormatter()) == null ? void 0 : u.getSelection();
!e || e.rangeCount === 0 || (e.getRangeAt(0).startContainer.textContent || "").lastIndexOf("@") === -1 || (this.savedCursor = this.editor.saveCursorPosition(), (l = this.popup) == null || l.show());
});
}
initialize(t) {
this.editor = t, this.popup = new m(t, {
title: t.t("Insert mention"),
className: "mentions-popup",
closeOnClickOutside: !0,
items: this.buildItems(),
buttons: [
{ label: t.t("Cancel"), variant: "secondary", onClick: () => {
var n;
return (n = this.popup) == null ? void 0 : n.hide();
} },
{ label: t.t("Insert"), variant: "primary", onClick: () => this.handleInsert() }
]
});
const e = t.getToolbar();
e && (this.toolbarButton = c({
icon: d,
title: t.t("Mentions"),
onClick: () => {
t.ensureEditorFocus(), this.savedCursor = t.saveCursorPosition(), requestAnimationFrame(() => {
var n;
(n = this.popup) == null || n.show();
});
}
}), e.appendChild(this.toolbarButton)), t.getContainer().addEventListener("input", this.onInput);
}
// removed dropdown; popup handles outside click itself
insertMentionText(t) {
var a;
if (!this.editor) return;
this.savedCursor ? this.editor.restoreCursorPosition(this.savedCursor) : this.editor.ensureEditorFocus();
const e = (a = this.editor.getTextFormatter()) == null ? void 0 : a.getSelection();
if (!e || e.rangeCount === 0) return;
const s = e.getRangeAt(0), n = document.createElement("span");
n.className = "mention", n.contentEditable = "false";
const r = t.trim().replace(/^@+/, "");
n.dataset.userId = r, n.textContent = `@${r}`, s.insertNode(n), s.setStartAfter(n), s.collapse(!0), e.removeAllRanges(), e.addRange(s), this.savedCursor = null;
}
buildItems() {
var t, e;
return [
{
type: "input",
id: "mention-value",
label: ((t = this.editor) == null ? void 0 : t.t("User")) || "User",
placeholder: ((e = this.editor) == null ? void 0 : e.t("Enter username or id")) || "Enter username or id",
value: ""
}
];
}
handleInsert() {
if (!this.editor || !this.popup) return;
const t = String(this.popup.getValue("mention-value") || "").trim();
if (!t) {
this.popup.hide();
return;
}
this.insertMentionText(t), this.popup.hide();
}
destroy() {
if (!this.editor) return;
this.editor.getContainer().removeEventListener("input", this.onInput), this.popup && (this.popup.destroy(), this.popup = null), this.toolbarButton && (this.toolbarButton.remove(), this.toolbarButton = null), this.editor.off("mentions"), this.editor.off("mention-insert"), this.editor.off("mention-error"), this.editor = null, this.savedCursor = null;
}
}
export {
b as MentionsPlugin
};