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

3 lines (2 loc) 7.43 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 */ "use strict";var r=Object.defineProperty;var a=(c,t,e)=>t in c?r(c,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):c[t]=e;var s=(c,t,e)=>a(c,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});;/* empty css */;/* empty css */const d=require("./components/BlockContextMenu.cjs"),l=require("./commands/BlockCommand.cjs"),h=require("./commands/MergeBlocksCommand.cjs"),k=require("../ToolbarPlugin/utils.cjs"),u=require("../../icons/block.svg.cjs"),B=require("../../utils/Resizer.cjs");class b{constructor(){s(this,"name","block");s(this,"hotkeys",[{keys:"Ctrl+Alt+N",description:"Insert block",command:"block",icon:"🧱"},{keys:"Ctrl+Alt+T",description:"Insert text block",command:"block-text",icon:"📝"},{keys:"Ctrl+Alt+C",description:"Insert container",command:"block-container",icon:"📦"}]);s(this,"editor",null);s(this,"contextMenu",null);s(this,"activeBlock",null);s(this,"currentResizer",null);s(this,"isProcessing",!1);s(this,"toolbarButton",null)}initialize(t){this.contextMenu=new d.BlockContextMenu(t),this.editor=t,this.addToolbarButton(),this.setupBlockEvents(),this.setupKeyboardEvents(),this.editor.on("block",()=>{this.insertBlock()}),this.editor.on("block-text",()=>{this.insertTextBlock()}),this.editor.on("block-container",()=>{this.insertContainerBlock()})}addToolbarButton(){var e,o;const t=(e=this.editor)==null?void 0:e.getToolbar();t&&(this.toolbarButton=k.createToolbarButton({icon:u.default,title:((o=this.editor)==null?void 0:o.t("Insert Block"))||"Insert Block",onClick:()=>this.insertBlock()}),t.appendChild(this.toolbarButton))}setupBlockEvents(){if(!this.editor)return;const t=this.editor.getContainer();this.handleBlockClick=this.handleBlockClick.bind(this),this.handleContextMenu=this.handleContextMenu.bind(this),this.handleBlockKeydown=this.handleBlockKeydown.bind(this),this.handleBlockBlur=this.handleBlockBlur.bind(this),this.handleBlockFocus=this.handleBlockFocus.bind(this),this.handleBlockMouseDown=this.handleBlockMouseDown.bind(this),t.addEventListener("click",this.handleBlockClick),t.addEventListener("contextmenu",this.handleContextMenu),t.addEventListener("keydown",this.handleBlockKeydown),t.addEventListener("blur",this.handleBlockBlur,!0),t.addEventListener("focus",this.handleBlockFocus,!0),t.addEventListener("mousedown",this.handleBlockMouseDown)}setupKeyboardEvents(){this.editor&&this.editor.on("keydown",t=>{if(t.key==="Enter"&&!t.shiftKey){const e=t.target,o=e.closest(".editor-block");o&&e.classList.contains("block-content")&&(t.preventDefault(),this.createNewBlockAfter(o))}if(t.key==="Tab"){const e=t.target,o=e.closest(".editor-block");if(o&&e.classList.contains("block-content"))if(t.preventDefault(),t.shiftKey){const n=o.previousElementSibling;if(n&&n.classList.contains("editor-block")){const i=n.querySelector(".block-content");i&&i.contentEditable==="true"&&i.focus()}}else{const n=o.nextElementSibling;if(n&&n.classList.contains("editor-block")){const i=n.querySelector(".block-content");i&&i.contentEditable==="true"&&i.focus()}}}})}handleBlockClick(t){if(this.isProcessing)return;const e=t.target.closest(".editor-block");if(!e){this.deactivateBlock();return}if(this.activeBlock===e){const o=e.querySelector(".block-content");e.getAttribute("data-block-type")==="text"&&o&&o.contentEditable!=="true"&&(o.contentEditable="true");return}this.deactivateBlock(),this.activateBlock(e),e.getAttribute("data-block-type")==="text"&&this.createResizer(e)}handleContextMenu(t){var o;const e=t.target.closest(".editor-block");if(e instanceof HTMLElement){t.preventDefault();const n=t.clientX,i=t.clientY;(o=this.contextMenu)==null||o.show(e,n,i)}}handleBlockKeydown(t){const e=t.target,o=e.closest(".editor-block");o&&(t.key==="Backspace"&&e.classList.contains("block-content")&&(e.textContent||"").length===0&&(t.preventDefault(),this.mergeWithPreviousBlock(o)),t.key==="Delete"&&e.classList.contains("block-content")&&(e.textContent||"").length===0&&(t.preventDefault(),this.mergeWithNextBlock(o)))}handleBlockBlur(t){var o;const e=(o=this.editor)==null?void 0:o.getContainer();e&&!e.contains(t.relatedTarget)&&setTimeout(()=>{this.autoMergeEmptyBlocks()},100)}handleBlockFocus(t){const e=t.target,o=e.closest(".editor-block");o&&e.classList.contains("block-content")&&this.activeBlock!==o&&(this.deactivateBlock(),this.activateBlock(o))}handleBlockMouseDown(t){const e=t.target;e.closest(".editor-block")&&e.classList.contains("block-content")&&e.contentEditable}activateBlock(t){this.activeBlock=t,t.classList.add("active");const e=t.querySelector(".block-content");e&&(t.getAttribute("data-block-type")==="text"?e.contentEditable="true":e.contentEditable="false")}deactivateBlock(){this.activeBlock&&this.activeBlock.classList.remove("active"),this.activeBlock=null,this.currentResizer&&(this.currentResizer.destroy(),this.currentResizer=null)}createResizer(t){this.currentResizer&&this.currentResizer.destroy(),this.currentResizer=new B.Resizer(t,{handleSize:8,handleColor:"#2563eb",onResizeStart:()=>{var e;(e=this.editor)==null||e.disableObserver(),this.isProcessing=!0},onResize:(e,o)=>{t.style.width=e+"px",t.style.height=o+"px"},onResizeEnd:()=>{var e;(e=this.editor)==null||e.enableObserver(),this.isProcessing=!1}})}insertBlock(){if(!this.editor)return;new l.BlockCommand(this.editor).execute()}insertTextBlock(){if(!this.editor)return;new l.BlockCommand(this.editor).execute({type:"text"})}insertContainerBlock(){if(!this.editor)return;new l.BlockCommand(this.editor).execute({type:"container"})}createNewBlockAfter(t){if(!this.editor)return;new l.BlockCommand(this.editor).execute({type:"text"})}mergeWithPreviousBlock(t){const e=t.previousElementSibling;e&&e.classList.contains("editor-block")&&this.mergeBlocks([e,t])}mergeWithNextBlock(t){const e=t.nextElementSibling;e&&e.classList.contains("editor-block")&&this.mergeBlocks([t,e])}mergeBlocks(t){if(!this.editor||t.length<2)return;const e=new h.MergeBlocksCommand(this.editor);e.setData({blocks:t}),e.execute()}autoMergeEmptyBlocks(){if(!this.editor)return;const e=this.editor.getContainer().querySelectorAll(".editor-block");for(const o of e){const n=o.querySelector(".block-content");if(n&&(!n.textContent||n.textContent.trim()==="")){const i=o.nextElementSibling;if(i&&i.classList.contains("editor-block")){this.mergeBlocks([o,i]);break}}}}destroy(){var t,e,o;if(this.editor){const n=this.editor.getContainer();n.removeEventListener("click",this.handleBlockClick),n.removeEventListener("contextmenu",this.handleContextMenu),n.removeEventListener("keydown",this.handleBlockKeydown),n.removeEventListener("blur",this.handleBlockBlur,!0),n.removeEventListener("focus",this.handleBlockFocus,!0),n.removeEventListener("mousedown",this.handleBlockMouseDown)}(t=this.editor)==null||t.off("block"),(e=this.editor)==null||e.off("block-text"),(o=this.editor)==null||o.off("block-container"),this.currentResizer&&(this.currentResizer.destroy(),this.currentResizer=null),this.contextMenu&&(this.contextMenu.destroy(),this.contextMenu=null),this.deactivateBlock(),this.toolbarButton&&(this.toolbarButton.remove(),this.toolbarButton=null),this.editor=null,this.activeBlock=null}}exports.BlockPlugin=b;