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

2 lines (1 loc) 8.59 kB
"use strict";var c=Object.defineProperty;var h=(s,e,t)=>e in s?c(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var a=(s,e,t)=>h(s,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("./src/core/Plugin.cjs"),g=require("./src/core/services/HTMLFormatter.cjs"),u=require("./src/core/services/LocaleManager.cjs"),f=require("./src/core/services/TextFormatter/index.cjs"),v=require("./src/core/services/Selector.cjs");class C{constructor(e){a(this,"innerContainer");a(this,"container");a(this,"plugins");a(this,"eventHandlers");a(this,"formatter");a(this,"localeManager");a(this,"contentChangeCallbacks",[]);a(this,"mutationObserver");a(this,"textFormatter",null);a(this,"selector");a(this,"_disableObserver",!1);this.container=document.createElement("div"),this.container.className="html-editor",this.container.contentEditable="true",this.localeManager=new u.LocaleManager,e.appendChild(this.container),this.innerContainer=e,this.plugins=new d.DefaultPluginManager,this.eventHandlers=new Map,this.formatter=new g.HTMLFormatter,this.textFormatter=new f.TextFormatter(this.container),this.selector=new v.Selector(this.container),this.container.addEventListener("click",()=>{this.container.focus()}),this.container.addEventListener("dragstart",t=>this.handleDragStart(t)),this.container.addEventListener("dragend",t=>this.handleDragEnd(t)),this.container.addEventListener("dragenter",t=>this.handleDragEnter(t)),this.container.addEventListener("dragover",t=>this.handleDragOver(t)),this.container.addEventListener("dragleave",t=>this.handleDragLeave(t)),this.container.addEventListener("drop",t=>this.handleDrop(t)),this.container.addEventListener("paste",t=>this.handlePaste(t)),document.addEventListener("selectionchange",t=>this.handleSelectionChange(t)),this.mutationObserver=new MutationObserver(t=>this.handleMutations(t)),this.mutationObserver.observe(this.container,{childList:!0,subtree:!0,characterData:!0,attributes:!0})}async handleSelectionChange(e){const t=window.getSelection();if(!t||t.rangeCount===0)return;const r=t.getRangeAt(0).commonAncestorContainer;this.isSelectionInsideEditor(r)&&this.triggerEvent("selectionchange",{event:e})}isSelectionInsideEditor(e){return e.nodeType===Node.TEXT_NODE?this.container.contains(e.parentElement):e.nodeType===Node.ELEMENT_NODE?this.container.contains(e):!1}handleMutations(e){e.some(n=>n.type==="childList"||n.type==="characterData"||n.type==="attributes")&&this.handleContentChange()}async handlePaste(e){e.preventDefault();const t=e.clipboardData;if(!t)return;const n=t.files,r=t.getData("text");n.length>0?this.handleFileDrop(n,e):r&&this.handleTextDrop(r)}handleDragStart(e){this.triggerEvent("drag-start",{e})}handleDragEnd(e){this.triggerEvent("drag-end",{e})}handleDragEnter(e){e.preventDefault(),this.container.classList.add("drag-overlay"),this.container.draggable=!0,this.triggerEvent("drag-enter",{e})}handleDragOver(e){e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="copy"),this.triggerEvent("drag-over",{e})}handleDragLeave(e){e.preventDefault(),this.container.classList.remove("drag-overlay"),this.container.draggable=!1,this.triggerEvent("drag-leave",{e})}handleDrop(e){if(e.preventDefault(),this.container.classList.remove("drag-overlay"),this.container.draggable=!1,e.dataTransfer){const t=e.dataTransfer.files,n=e.dataTransfer.getData("text");t.length>0?this.handleFileDrop(t,e):n&&this.handleTextDrop(n)}this.triggerEvent("drag-drop",{e})}async handleFileDrop(e,t){for(let n=0;n<e.length;n++){const r=e[n],i=r.type,l=r.name,o=await this.readFileContent(r);this.triggerEvent("file-drop",{type:i,name:l,content:o,e:t})}}handleTextDrop(e){this.insertTextAtCursor(e),this.triggerEvent("text-drop",e)}async readFileContent(e){return new Promise((t,n)=>{const r=new FileReader;r.onload=()=>{r.result?t(r.result):n(new Error("Failed to read file"))},r.onerror=()=>n(r.error),e.type.startsWith("text/")?r.readAsText(e):r.readAsDataURL(e)})}insertTextAtCursor(e){const t=window.getSelection();if(t&&t.rangeCount>0){const n=t.getRangeAt(0);n.deleteContents(),n.insertNode(document.createTextNode(e)),n.collapse(!1)}}getContainer(){return this.container}getInnerContainer(){return this.innerContainer}getTextFormatter(){return this.textFormatter}getSelector(){return this.selector}isSelectionInsideContainer(e){if(!e||e.rangeCount===0)return!1;const t=e.getRangeAt(0);return this.container.contains(t.startContainer)&&this.container.contains(t.endContainer)}getSelectionInsideContainer(){const e=window.getSelection();return e&&this.isSelectionInsideContainer(e)?e:null}saveCursorPosition(){const e=this.getSelectionInsideContainer();if(!e||e.rangeCount===0)return null;const t=e.getRangeAt(0),n=t.cloneRange();return n.selectNodeContents(this.container),n.setEnd(t.startContainer,t.startOffset),{offset:n.toString().length}}restoreCursorPosition(e){const t=window.getSelection();if(!t)return;const n=document.createRange();let r=this.container,i=e.offset;const l=document.createTreeWalker(this.container,NodeFilter.SHOW_TEXT);for(;l.nextNode();){const o=l.currentNode;if(i<=o.length){r=o;break}i-=o.length}(r.nodeType!==Node.TEXT_NODE||i<0||i>r.length)&&(r=this.container,i=this.container.childNodes.length),n.setStart(r,i),n.collapse(!0),t.removeAllRanges(),t.addRange(n),this.container.focus()}use(e){this.plugins.register(e),e.initialize(this)}getPlugins(){return this.plugins.getPlugins()}getHotkeys(){return this.plugins.getHotkeys()}on(e,t){return this.eventHandlers.has(e)||this.eventHandlers.set(e,[]),this.eventHandlers.get(e).push(t),()=>{const n=this.eventHandlers.get(e);if(n){const r=n.indexOf(t);r!==-1&&n.splice(r,1),n.length===0&&this.eventHandlers.delete(e)}}}triggerEvent(e,...t){const n=this.eventHandlers.get(e);n&&n.forEach(r=>r(...t))}off(e,t){if(this.eventHandlers.has(e))if(t){const n=this.eventHandlers.get(e),r=n.indexOf(t);r!==-1&&n.splice(r,1),n.length===0&&this.eventHandlers.delete(e)}else this.eventHandlers.delete(e)}disableObserver(){this._disableObserver=!0}enableObserver(){this._disableObserver=!1}handleContentChange(){if(this._disableObserver)return;const e=this.getHtml();this.contentChangeCallbacks.forEach(t=>t(e))}subscribeToContentChange(e){return this.contentChangeCallbacks.push(e),()=>{const t=this.contentChangeCallbacks.indexOf(e);t!==-1&&this.contentChangeCallbacks.splice(t,1)}}ensureEditorFocus(){const e=this.getContainer();e.focus();const t=window.getSelection();if(!t||!t.rangeCount){const n=document.createRange();n.selectNodeContents(e),n.collapse(!0),t==null||t.removeAllRanges(),t==null||t.addRange(n)}}getHtml(){const e=this.getContainer();if(!e)return"";const n=e.cloneNode(!0).innerHTML;return this.formatter.format(n)}waitForDOMStabilization(e,t=100){return new Promise(n=>{let r;const i=new MutationObserver(()=>{clearTimeout(r),r=setTimeout(()=>{i.disconnect(),n()},t)});i.observe(e,{childList:!0,subtree:!0,attributes:!0,characterData:!0}),r=setTimeout(()=>{i.disconnect(),n()},t)})}async setHtml(e){await this.waitForDOMStabilization(this.container),this.container.innerHTML=this.formatter.format(e),await new Promise(t=>requestAnimationFrame(t))}insertContent(e){this.ensureEditorFocus();const t=window.getSelection();if(t&&t.rangeCount>0){const n=t.getRangeAt(0);if(n.deleteContents(),typeof e=="string"){const r=document.createElement("div");for(r.innerHTML=e;r.firstChild;)n.insertNode(r.firstChild)}else n.insertNode(e);n.collapse(!1),t.removeAllRanges(),t.addRange(n)}else{const n=this.getContainer();typeof e=="string"?n.insertAdjacentHTML("beforeend",e):n.appendChild(e)}}t(e,t={}){return this.localeManager.translate(e,t)}async setLocale(e){return await this.localeManager.setLocale(e)}getLocale(){return this.localeManager.getCurrentLocale()}destroy(){this.mutationObserver.disconnect(),this.container.removeEventListener("click",()=>this.container.focus()),this.container.removeEventListener("dragenter",e=>this.handleDragEnter(e)),this.container.removeEventListener("dragover",e=>this.handleDragOver(e)),this.container.removeEventListener("dragleave",e=>this.handleDragLeave(e)),this.container.removeEventListener("drop",e=>this.handleDrop(e)),this.container.removeEventListener("paste",e=>this.handlePaste(e)),this.contentChangeCallbacks=[],this.plugins.destroy(),this.container.parentElement&&this.container.parentElement.removeChild(this.container),this.innerContainer=null,this.container=null,this.plugins=null,this.eventHandlers=null,this.formatter=null,this.localeManager=null,this.mutationObserver=null,this.textFormatter=null}}exports.HTMLEditor=C;