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
235 lines (234 loc) • 7.46 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 s = Object.defineProperty;
var a = (n, t, e) => t in n ? s(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
var c = (n, t, e) => a(n, typeof t != "symbol" ? t + "" : t, e);
import r from "../../../icons/delete.svg.mjs";
import k from "../../../icons/duplicate.svg.mjs";
import h from "../../../icons/move.svg.mjs";
import l from "../../../icons/split-horizontal.svg.mjs";
import m from "../../../icons/split-vertical.svg.mjs";
import { ContextMenu as u } from "../../../core/ui/ContextMenu.mjs";
import { SplitBlockCommand as p } from "../commands/SplitBlockCommand.mjs";
import { MergeBlocksCommand as d } from "../commands/MergeBlocksCommand.mjs";
import { BlockCommand as B } from "../commands/BlockCommand.mjs";
import { DuplicateBlockCommand as v } from "../commands/DuplicateBlockCommand.mjs";
import { DeleteBlockCommand as b } from "../commands/DeleteBlockCommand.mjs";
class I {
constructor(t) {
c(this, "editor");
c(this, "contextMenu");
c(this, "activeBlock", null);
this.editor = t, this.contextMenu = new u(
t,
[
{
title: t.t("Insert"),
icon: "➕",
subMenu: [
{
title: t.t("Text Block"),
action: "insert-text",
onClick: () => this.handleAction("insert-text")
},
{
title: t.t("Container Block"),
action: "insert-container",
onClick: () => this.handleAction("insert-container")
},
{
title: t.t("Split Container"),
action: "insert-split",
onClick: () => this.handleAction("insert-split")
}
]
},
{
title: t.t("Split"),
icon: l,
subMenu: [
{
title: t.t("Horizontally"),
icon: l,
action: "split-horizontal",
onClick: () => this.handleAction("split-horizontal")
},
{
title: t.t("Vertically"),
icon: m,
action: "split-vertical",
onClick: () => this.handleAction("split-vertical")
}
]
},
{
title: t.t("Merge"),
icon: "🔗",
action: "merge",
onClick: () => this.handleAction("merge")
},
{
type: "divider"
},
{
title: t.t("Move"),
icon: h,
subMenu: [
{
title: t.t("Up"),
action: "move-up",
onClick: () => this.handleAction("move-up")
},
{
title: t.t("Down"),
action: "move-down",
onClick: () => this.handleAction("move-down")
}
]
},
{
title: t.t("Duplicate"),
icon: k,
action: "duplicate",
onClick: () => this.handleAction("duplicate")
},
{
type: "divider"
},
{
title: t.t("Settings"),
icon: "🔧",
subMenu: [
{
title: t.t("Make Editable"),
action: "make-editable",
onClick: () => this.handleAction("make-editable")
},
{
title: t.t("Make Read-only"),
action: "make-readonly",
onClick: () => this.handleAction("make-readonly")
}
]
},
{
title: t.t("Remove"),
icon: r,
action: "remove",
className: "text-red-600",
onClick: () => this.handleAction("remove")
}
],
{ orientation: "vertical" }
);
}
handleAction(t) {
if (this.activeBlock) {
switch (t) {
case "insert-text":
this.insertBlock("text");
break;
case "insert-container":
this.insertBlock("container");
break;
case "insert-split":
this.insertBlock("split");
break;
case "split-horizontal":
this.splitBlock("horizontal");
break;
case "split-vertical":
this.splitBlock("vertical");
break;
case "merge":
this.mergeBlocks();
break;
case "move-up":
this.moveBlock("up");
break;
case "move-down":
this.moveBlock("down");
break;
case "duplicate":
this.duplicateBlock();
break;
case "make-editable":
this.setBlockEditable(!0);
break;
case "make-readonly":
this.setBlockEditable(!1);
break;
case "remove":
this.removeBlock();
break;
}
this.hide();
}
}
insertBlock(t) {
new B(this.editor).execute({ type: t });
}
splitBlock(t) {
if (!this.activeBlock || !this.canSplit(this.activeBlock)) return;
const e = new p(this.editor);
e.setData({ direction: t, block: this.activeBlock }), e.execute();
}
mergeBlocks() {
if (!this.activeBlock) return;
const t = this.getAdjacentBlocks(this.activeBlock);
if (t.length < 2) return;
const e = new d(this.editor);
e.setData({ blocks: t }), e.execute();
}
moveBlock(t) {
var e, o;
if (this.activeBlock)
if (t === "up") {
const i = this.activeBlock.previousElementSibling;
i && i.classList.contains("editor-block") && ((e = i.parentNode) == null || e.insertBefore(this.activeBlock, i));
} else {
const i = this.activeBlock.nextElementSibling;
i && i.classList.contains("editor-block") && ((o = i.parentNode) == null || o.insertBefore(i, this.activeBlock));
}
}
duplicateBlock() {
if (!this.activeBlock) return;
const t = new v(this.editor);
t.setData({ block: this.activeBlock }), t.execute();
}
setBlockEditable(t) {
if (!this.activeBlock) return;
const e = this.activeBlock.querySelector(".block-content");
e && (e.contentEditable = t.toString());
}
removeBlock() {
if (!this.activeBlock) return;
const t = new b(this.editor);
t.setBlock(this.activeBlock), t.execute();
}
canSplit(t) {
return t.classList.contains("editor-block") && !t.classList.contains("split-container") && t.getAttribute("data-block-type") === "text";
}
getAdjacentBlocks(t) {
const e = [];
e.push(t);
let o = t.previousElementSibling;
for (; o && o.classList.contains("editor-block") && o.getAttribute("data-block-type") === "text"; )
e.unshift(o), o = o.previousElementSibling;
let i = t.nextElementSibling;
for (; i && i.classList.contains("editor-block") && i.getAttribute("data-block-type") === "text"; )
e.push(i), i = i.nextElementSibling;
return e;
}
show(t, e, o) {
this.activeBlock = t, this.contextMenu.show(t, e, o);
}
hide() {
this.contextMenu.hide(), this.activeBlock = null;
}
destroy() {
this.contextMenu && typeof this.contextMenu.destroy == "function" && this.contextMenu.destroy(), this.editor = null, this.contextMenu = null, this.activeBlock = null;
}
}
export {
I as BlockContextMenu
};