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
119 lines (118 loc) • 5.05 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 f = Object.defineProperty;
var m = (a, t, e) => t in a ? f(a, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[t] = e;
var d = (a, t, e) => m(a, typeof t != "symbol" ? t + "" : t, e);
import { PopupManager as y } from "../../../core/ui/PopupManager.mjs";
import { formatTimestamp as x } from "../utils/formatters.mjs";
import { computeDiff as v } from "../utils/diff.mjs";
import C from "../../../icons/close.svg.mjs";
import { createContainer as n, createH as g, createButton as u } from "../../../utils/helpers.mjs";
class R {
constructor(t) {
d(this, "editor");
d(this, "popup");
d(this, "states", []);
d(this, "currentIndex", -1);
d(this, "selectedIndex", -1);
d(this, "onRestore", null);
this.editor = t, this.popup = new y(t, {
className: "history-viewer-modal",
closeOnClickOutside: !0,
items: [
{
type: "custom",
id: "html-viewer-content",
content: () => this.createContent()
}
]
});
}
createContent() {
const t = n("p-4"), e = n("flex items-center justify-between mb-4"), s = g("h3", "text-lg font-semibold", this.editor.t("Edit History")), i = u("", () => {
this.popup.hide();
});
i.className = "close-button", i.innerHTML = C, e.appendChild(s), e.appendChild(i);
const o = n("grid grid-cols-2 gap-4"), r = n("history-list max-h-[60vh] overflow-y-auto"), c = n(
"diff-view max-h-[60vh] overflow-y-auto p-3 bg-gray-50 rounded-lg"
);
return o.appendChild(r), o.appendChild(c), t.appendChild(e), t.appendChild(o), t.addEventListener("click", (p) => {
const l = p.target.closest("[data-index]");
if (!l) return;
const h = parseInt(l.getAttribute("data-index") || "0", 10);
this.selectedIndex = h, this.showDiff(h);
}), t;
}
renderHistoryList() {
const t = this.popup.getElement().querySelector(".history-list");
t && (t.innerHTML = "", this.states.forEach((e, s) => {
const i = this.createHistoryItem(e, s);
t.appendChild(i);
}));
}
createHistoryItem(t, e) {
const s = n(
`history-item ${e === this.currentIndex ? "current" : ""} ${e === this.selectedIndex ? "selected" : ""}`
);
s.dataset.index = e.toString();
const i = n(
"flex items-center justify-between p-3 hover:bg-gray-50 rounded-lg cursor-pointer"
), o = n(), r = n("text-sm font-medium");
r.textContent = `Version ${e + 1}`;
const c = n("ext-xs text-gray-500", x(t.timestamp));
o.appendChild(r), o.appendChild(c);
const p = u(this.editor.t("Restore"), (l) => {
l.preventDefault();
const h = this.states[e];
h && this.onRestore && (this.onRestore(h.content), this.popup.hide());
});
return p.className = "restore-button px-2 py-1 text-sm text-blue-600 hover:bg-blue-50 rounded", p.textContent = this.editor.t("Restore"), i.appendChild(o), i.appendChild(p), s.appendChild(i), s;
}
showDiff(t) {
const e = this.popup.getElement().querySelector(".diff-view");
if (!e) return;
const s = this.states[t], i = t > 0 ? this.states[t - 1] : { content: "" }, o = v(i.content, s.content), r = this.renderDiff(o);
e.innerHTML = "";
const c = n("text-sm mb-2 text-gray-500");
c.textContent = t > 0 ? this.editor.t("Changes from previous version:") : this.editor.t("Initial version");
const p = n("diff-content");
p.innerHTML = r, e.appendChild(c), e.appendChild(p);
}
renderDiff(t) {
return t.map((e) => {
switch (e.type) {
case "add":
return `<span class="diff-add">${e.value}</span>`;
case "remove":
return `<span class="diff-remove">${e.value}</span>`;
default:
return e.value;
}
}).join("");
}
show(t, e, s) {
this.states = t, this.currentIndex = e, this.selectedIndex = e, this.onRestore = s, this.renderHistoryList(), this.showDiff(e), this.popup.show();
}
destroy() {
this.popup.destroy && this.popup.destroy();
const t = this.popup.getElement();
if (t) {
const e = t.querySelector(".close-button");
e == null || e.removeEventListener("click", () => {
this.popup.hide();
}), t.removeEventListener("click", (s) => {
const i = s.target.closest("[data-index]");
if (!i) return;
const o = parseInt(i.getAttribute("data-index") || "0", 10);
if (s.target.closest(".restore-button")) {
const r = this.states[o];
r && this.onRestore && (this.onRestore(r.content), this.popup.hide());
} else
this.selectedIndex = o, this.showDiff(o);
});
}
this.states = [], this.currentIndex = -1, this.selectedIndex = -1, this.onRestore = null, this.editor = null, this.popup = null;
}
}
export {
R as HistoryViewerModal
};