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
218 lines (217 loc) • 11.1 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 = (d, e, t) => e in d ? p(d, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[e] = t;
var r = (d, e, t) => h(d, typeof e != "symbol" ? e + "" : e, t);
/* empty css */
/* empty css */
import { ResponsiveMenu as c } from "./components/ResponsiveMenu.mjs";
import { ViewportManager as u } from "./services/ViewportManager.mjs";
import v from "../../icons/desktop.svg.mjs";
import w from "../../icons/mobile.svg.mjs";
import m from "../../icons/responsive.svg.mjs";
import g from "../../icons/tablet.svg.mjs";
class H {
constructor() {
r(this, "name", "responsive");
r(this, "hotkeys", [
{ keys: "Ctrl+1", description: "Mobile View", command: "responsive-mobile", icon: "📱" },
{ keys: "Ctrl+2", description: "Tablet View", command: "responsive-tablet", icon: "📱" },
{ keys: "Ctrl+3", description: "Desktop View", command: "responsive-desktop", icon: "💻" },
{ keys: "Ctrl+4", description: "Large Desktop View", command: "responsive-large", icon: "💻" },
{ keys: "Ctrl+5", description: "Ultra Wide View", command: "responsive-ultra", icon: "💻" },
{ keys: "Ctrl+0", description: "Responsive View", command: "responsive-fluid", icon: "🔄" },
{ keys: "Ctrl+Alt+R", description: "Responsive Menu", command: "responsive", icon: "🔄" }
]);
r(this, "editor", null);
r(this, "menu", null);
r(this, "viewportManager");
r(this, "toolbarButton", null);
r(this, "viewportIndicator", null);
r(this, "resizeHandle", null);
r(this, "isResizing", !1);
r(this, "startX", 0);
r(this, "startWidth", 0);
r(this, "boundHotkeysKeydown");
r(this, "onResize", (e) => {
if (!this.isResizing || !this.editor) return;
const t = e.clientX - this.startX;
let i = this.startWidth + t;
i = Math.max(320, Math.min(i, 1920));
const s = this.editor.getContainer();
s.style.width = i + "px", s.style.maxWidth = i + "px", localStorage.setItem("responsive-custom-width", String(i));
});
r(this, "stopResize", (e) => {
var t, i;
this.isResizing && (this.isResizing = !1, document.body.style.cursor = "", (t = this.editor) == null || t.getDOMContext().removeEventListener("mousemove", this.onResize), (i = this.editor) == null || i.getDOMContext().removeEventListener("mouseup", this.stopResize));
});
this.viewportManager = new u();
}
initialize(e) {
this.menu = new c(e), this.editor = e, this.addViewportIndicator(), this.setupViewportControls(), this.setupHotkeys(), this.editor.on("responsive", () => {
var t, i;
(t = this.editor) == null || t.ensureEditorFocus(), (i = this.menu) == null || i.show();
}), this.editor.on("responsive-mobile", () => {
this.setViewport("mobile");
}), this.editor.on("responsive-tablet", () => {
this.setViewport("tablet");
}), this.editor.on("responsive-desktop", () => {
this.setViewport("desktop");
}), this.editor.on("responsive-large", () => {
this.setViewport("largeDesktop");
}), this.editor.on("responsive-ultra", () => {
this.setViewport("ultraWide");
}), this.editor.on("responsive-fluid", () => {
this.setViewport("responsive");
});
}
addViewportIndicator() {
var t, i, s;
const e = (t = this.editor) == null ? void 0 : t.getToolbar();
e && (this.viewportIndicator = document.createElement("div"), this.viewportIndicator.className = "viewport-indicator flex items-center gap-2 px-3 py-1 bg-gray-100 rounded-lg text-sm font-medium text-gray-700 cursor-pointer hover:bg-gray-200 transition-colors", this.viewportIndicator.title = ((i = this.editor) == null ? void 0 : i.t("Current viewport - Click to change")) || "Current viewport - Click to change", this.updateViewportIndicator(), this.viewportIndicator.addEventListener("click", () => {
var o;
(o = this.menu) == null || o.show();
}), this.toolbarButton ? (s = this.toolbarButton.parentNode) == null || s.insertBefore(
this.viewportIndicator,
this.toolbarButton.nextSibling
) : e.appendChild(this.viewportIndicator));
}
updateViewportIndicator() {
if (!this.viewportIndicator) return;
const e = this.viewportManager.getCurrentViewport(), t = this.viewportManager.getCurrentWidth();
let i = m;
switch (e) {
case "mobile":
i = w;
break;
case "tablet":
i = g;
break;
case "desktop":
case "largeDesktop":
case "ultraWide":
i = v;
break;
}
this.viewportIndicator.innerHTML = `
<span class="viewport-icon">${i}</span>
<span class="viewport-label">${this.getViewportLabel(e)}</span>
<span class="viewport-width text-xs text-gray-500">${t}px</span>
`;
}
getViewportLabel(e) {
var i, s, o, a, n, l;
return {
mobile: ((i = this.editor) == null ? void 0 : i.t("Mobile")) || "Mobile",
tablet: ((s = this.editor) == null ? void 0 : s.t("Tablet")) || "Tablet",
desktop: ((o = this.editor) == null ? void 0 : o.t("Desktop")) || "Desktop",
largeDesktop: ((a = this.editor) == null ? void 0 : a.t("Large")) || "Large",
ultraWide: ((n = this.editor) == null ? void 0 : n.t("Ultra")) || "Ultra",
responsive: ((l = this.editor) == null ? void 0 : l.t("Fluid")) || "Fluid"
}[e] || e;
}
setupViewportControls() {
var i;
if (!this.editor) return;
const e = this.editor.getContainer(), t = this.viewportManager.getCurrentViewport();
this.viewportManager.setViewport(e, t), (i = this.menu) == null || i.onViewportChange((s) => {
var o;
this.viewportManager.setViewport(e, s), this.updateViewportIndicator(), (o = this.editor) == null || o.triggerEvent("viewportChanged", {
viewport: s,
width: this.viewportManager.getCurrentWidth()
}), this.adaptTablesToViewport(s), this.removeResizeHandle(), s === "responsive" && (localStorage.removeItem("responsive-custom-width"), e.style.width = "100%", e.style.maxWidth = "none", setTimeout(() => {
this.addResizeHandle();
}, 0));
}), this.viewportManager.onViewportChange((s, o) => {
var a;
if (this.updateViewportIndicator(), (a = this.editor) == null || a.triggerEvent("viewportChanged", { viewport: s, width: o }), this.adaptTablesToViewport(s), this.removeResizeHandle(), s === "responsive") {
const n = localStorage.getItem("responsive-custom-width");
n && (e.style.width = n + "px", e.style.maxWidth = n + "px"), setTimeout(() => {
this.addResizeHandle();
}, 0);
}
}), t === "responsive" && (localStorage.removeItem("responsive-custom-width"), e.style.width = "100%", e.style.maxWidth = "none", setTimeout(() => {
this.addResizeHandle();
}, 0));
}
adaptTablesToViewport(e) {
if (!this.editor) return;
this.editor.getContainer().querySelectorAll(".html-editor-table").forEach((s) => {
const o = s;
switch (o.classList.remove("responsive-table"), o.classList.remove(
"breakpoint-320",
"breakpoint-768",
"breakpoint-1024",
"breakpoint-1440",
"breakpoint-1920"
), e) {
case "mobile":
o.classList.add("responsive-table", "breakpoint-320");
break;
case "tablet":
o.classList.add("responsive-table", "breakpoint-768");
break;
case "desktop":
o.classList.add("responsive-table", "breakpoint-1024");
break;
case "largeDesktop":
o.classList.add("responsive-table", "breakpoint-1440");
break;
case "ultraWide":
o.classList.add("responsive-table", "breakpoint-1920");
break;
}
});
}
setupHotkeys() {
var e;
this.boundHotkeysKeydown = (t) => {
var i, s;
if (t.ctrlKey && !t.shiftKey && !t.altKey) {
const o = t.key, a = {
1: "mobile",
2: "tablet",
3: "desktop",
4: "largeDesktop",
5: "ultraWide",
0: "responsive"
};
if (a[o]) {
t.preventDefault();
const n = (i = this.editor) == null ? void 0 : i.getContainer();
n && this.viewportManager.setViewport(n, a[o]);
}
}
t.ctrlKey && (t.key === "ArrowLeft" || t.key === "ArrowRight") && (t.preventDefault(), (s = this.editor) != null && s.getContainer() && (t.key === "ArrowRight" ? this.viewportManager.nextViewport() : this.viewportManager.previousViewport()));
}, (e = this.editor) == null || e.getDOMContext().addEventListener("keydown", this.boundHotkeysKeydown);
}
setViewport(e) {
var i;
const t = (i = this.editor) == null ? void 0 : i.getContainer();
t && this.viewportManager.setViewport(t, e);
}
getCurrentViewport() {
return this.viewportManager.getCurrentViewport();
}
getCurrentWidth() {
return this.viewportManager.getCurrentWidth();
}
addResizeHandle() {
if (!this.editor) return;
const e = this.editor.getContainer();
this.removeResizeHandle(), this.viewportManager.getCurrentViewport() === "responsive" && (e.style.position = "relative", this.resizeHandle = document.createElement("div"), this.resizeHandle.className = "html-editor-responsive-resize-handle", this.resizeHandle.title = this.editor.t("Resize editor width"), e.appendChild(this.resizeHandle), this.resizeHandle.addEventListener("mousedown", (t) => this.startResize(t)));
}
removeResizeHandle() {
this.resizeHandle && this.resizeHandle.parentElement && this.resizeHandle.parentElement.removeChild(this.resizeHandle), this.resizeHandle = null;
}
startResize(e) {
var t, i;
this.editor && this.viewportManager.getCurrentViewport() === "responsive" && (this.isResizing = !0, this.startX = e.clientX, this.startWidth = this.editor.getContainer().offsetWidth, document.body.style.cursor = "ew-resize", (t = this.editor) == null || t.getDOMContext().addEventListener("mousemove", this.onResize), (i = this.editor) == null || i.getDOMContext().addEventListener("mouseup", this.stopResize));
}
destroy() {
var e, t;
this.toolbarButton && this.toolbarButton.parentElement && this.toolbarButton.parentElement.removeChild(this.toolbarButton), this.viewportIndicator && this.viewportIndicator.parentElement && this.viewportIndicator.parentElement.removeChild(this.viewportIndicator), this.menu && (this.menu.destroy(), this.menu = null), this.viewportManager.destroy(), (e = this.editor) == null || e.off("responsive"), this.boundHotkeysKeydown && ((t = this.editor) == null || t.getDOMContext().removeEventListener("keydown", this.boundHotkeysKeydown), this.boundHotkeysKeydown = void 0), this.editor = null, this.toolbarButton = null, this.viewportIndicator = null, this.removeResizeHandle();
}
}
export {
H as ResponsivePlugin
};