UNPKG

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

163 lines (162 loc) 6.66 kB
/*! 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 f = (h, t, e) => t in h ? p(h, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : h[t] = e; var m = (h, t, e) => f(h, typeof t != "symbol" ? t + "" : t, e); /* empty css */ /* empty css */ import { CommentManager as C } from "./services/CommentManager.mjs"; import { CommentMenu as g } from "./components/CommentMenu.mjs"; import { ErrorModal as M } from "./components/ErrorModal.mjs"; import { createToolbarButton as k } from "../ToolbarPlugin/utils.mjs"; import v from "../../icons/comment.svg.mjs"; import b from "../../icons/comment-marker.svg.mjs"; import { createContainer as y, createSpan as c } from "../../utils/helpers.mjs"; class S { constructor() { m(this, "name", "comments"); m(this, "hotkeys", [{ keys: "Ctrl+Alt+J", description: "Insert comment", command: "comment", icon: "💬" }]); m(this, "editor", null); m(this, "manager"); m(this, "menu", null); m(this, "errorModal", null); m(this, "tooltip"); m(this, "toolbarButton", null); this.manager = new C(), this.tooltip = this.createTooltip(); } initialize(t) { this.errorModal = new M(t), this.menu = new g(t), this.editor = t, this.editor.getDOMContext().appendChild(this.tooltip), this.addToolbarButton(), this.setupEventListeners(), this.editor.on("comment", () => { this.addComment(); }); } createTooltip() { const t = y("comment-tooltip"); return t.style.display = "none", t; } addToolbarButton() { var e, o; const t = (e = this.editor) == null ? void 0 : e.getToolbar(); t && (this.toolbarButton = k({ icon: v, title: (o = this.editor) == null ? void 0 : o.t("Insert Comment"), onClick: () => this.addComment() }), t.appendChild(this.toolbarButton)); } setupEventListeners() { this.editor && (this.handleMouseOver = this.handleMouseOver.bind(this), this.handleMouseOut = this.handleMouseOut.bind(this), this.handleClick = this.handleClick.bind(this)); } handleMouseOver(t) { const e = t.target.closest(".comment-marker"); if (e instanceof HTMLElement) { const o = e.getAttribute("data-comment-id"); o && this.showTooltip(e, o); } } handleMouseOut(t) { t.target.closest(".comment-marker") && this.hideTooltip(); } handleClick(t) { const e = t.target.closest(".comment-marker"); if (e instanceof HTMLElement) { const o = e.getAttribute("data-comment-id"); o && this.editComment(o); } } showTooltip(t, e) { const o = this.manager.getComment(e); if (!o) return; this.tooltip.textContent = o.content, this.tooltip.style.display = "block"; const n = t.getBoundingClientRect(); this.tooltip.style.left = `${n.left + n.width / 2}px`, this.tooltip.style.top = `${n.bottom + 8}px`; } hideTooltip() { this.tooltip.style.display = "none"; } addComment() { var o, n, l, r, s, i; if (!this.editor) { (o = this.errorModal) == null || o.show("Editor not initialized"); return; } const t = (n = this.editor.getTextFormatter()) == null ? void 0 : n.getSelection(); if (!t || !t.rangeCount) { (l = this.errorModal) == null || l.show(this.editor.t("Please select some text to comment on")); return; } const e = t.getRangeAt(0); if (!this.isRangeInsideEditor(e)) { (r = this.errorModal) == null || r.show(this.editor.t("Please select text inside the editor")); return; } if (e.collapsed) { (s = this.errorModal) == null || s.show(this.editor.t("Please select some text to comment on")); return; } (i = this.menu) == null || i.show((a, d) => { if (d === "save") { const u = this.manager.createComment(a); this.insertCommentMarker(u.id, e); } }); } isRangeInsideEditor(t) { var o; const e = (o = this.editor) == null ? void 0 : o.getContainer(); return e ? e.contains(t.startContainer) && e.contains(t.endContainer) : !1; } editComment(t) { var o; const e = this.manager.getComment(t); e && ((o = this.menu) == null || o.show( (n, l) => { var r; if (l === "save") this.manager.updateComment(t, n); else if (l === "delete") { this.manager.deleteComment(t); const s = (r = this.editor) == null ? void 0 : r.getContainer().querySelector(`[data-comment-id="${t}"]`); if (s) { const i = s.previousElementSibling; if (i != null && i.classList.contains("commented-text")) { const a = i.parentNode; if (a) { for (; i.firstChild; ) a.insertBefore(i.firstChild, i); i.remove(), s.remove(); } } } } }, e.content, !0 )); } insertCommentMarker(t, e) { var o, n, l; try { const r = e.cloneContents(), s = c("commented-text"); s.appendChild(r); const i = c("comment-marker"); i.setAttribute("data-comment-id", t), i.innerHTML = b; const a = document.createDocumentFragment(); a.appendChild(s), a.appendChild(i), e.deleteContents(), e.insertNode(a), e.setStartAfter(i), e.setEndAfter(i); const d = (o = this.editor.getTextFormatter()) == null ? void 0 : o.getSelection(); d && (d.removeAllRanges(), d.addRange(e)); } catch (r) { console.error("Failed to insert comment:", r), (l = this.errorModal) == null || l.show( ((n = this.editor) == null ? void 0 : n.t("Failed to insert comment. Please try selecting a simpler text range.")) ?? "" ); } } destroy() { var t; if (this.editor) { const e = this.editor.getContainer(); e.removeEventListener("mouseover", this.handleMouseOver), e.removeEventListener("mouseout", this.handleMouseOut), e.removeEventListener("click", this.handleClick); } this.tooltip && this.tooltip.parentElement && this.tooltip.parentElement.removeChild(this.tooltip), this.toolbarButton && (this.toolbarButton.remove(), this.toolbarButton = null), this.menu && (this.menu.destroy(), this.menu = null), this.errorModal && (this.errorModal.destroy(), this.errorModal = null), (t = this.editor) == null || t.off("comment"), this.editor = null, this.menu = null, this.errorModal = null, this.tooltip = null, this.manager = null; } } export { S as CommentsPlugin };