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) • 5.03 kB
JavaScript
"use strict";var l=Object.defineProperty;var c=(i,t,e)=>t in i?l(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var n=(i,t,e)=>c(i,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("../../core/ui/PopupManager.cjs"),u=require("../ToolbarPlugin/utils.cjs"),h=require("../../icons/collaboration.svg.cjs"),a=require("../../utils/helpers.cjs");function r(i=8){const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";let e="";for(let o=0;o<i;o++)e+=t.charAt(Math.floor(Math.random()*t.length));return e}class p{constructor(t={}){n(this,"name","collaboration");n(this,"hotkeys",[{keys:"Ctrl+Shift+C",description:"Enable collaboration mode",command:"collaboration",icon:"👥"}]);n(this,"editor",null);n(this,"ws",null);n(this,"docId",null);n(this,"popup",null);n(this,"options");n(this,"toolbarButton",null);n(this,"isExternalUpdate",!1);n(this,"contentVersion",0);n(this,"lastContent","");n(this,"unsubscribeFromContentChange",null);n(this,"status","");n(this,"userId","");n(this,"debouncedSendUpdate",this.debounce(t=>{this.ws&&this.docId&&this.status==="Connected"&&(this.ws.send(JSON.stringify({type:"update",docId:this.docId,userId:this.userId,content:t,version:this.contentVersion})),console.log("Content sent:",t))},300));this.options={serverUrl:"ws://localhost:8080",autoStart:!0,...t}}initialize(t){const e=new URLSearchParams(window.location.search);this.userId=e.get("userId")??r(),this.editor=t,this.popup=new d.PopupManager(this.editor,{title:"Collaboration",closeOnClickOutside:!1,buttons:[{label:"Start Collaboration",variant:"primary",onClick:()=>this.startCollaboration()}],items:[{type:"custom",id:"collaboration-content",content:()=>this.createCollaborationContent()}]}),this.options.autoStart&&this.setupCollaboration(),this.addToolbarButton(),this.editor.on("collaboration",()=>{var o;(o=this.popup)==null||o.show()})}addToolbarButton(){var e;const t=document.querySelector(".editor-toolbar");t&&(this.toolbarButton=u.createToolbarButton({icon:h.default,title:(e=this.editor)==null?void 0:e.t("Collaboration"),onClick:()=>{var o;return(o=this.popup)==null?void 0:o.show()}}),t.appendChild(this.toolbarButton))}updateConnectionStatus(t){if(this.status=t,!this.editor)return;const e=this.editor.getInnerContainer().querySelector(".collaboration-status");e&&(e.textContent=this.editor.t("Collaboration")+": "+t)}setupCollaboration(){if(!this.editor||!this.options.serverUrl)return;const t=new URLSearchParams(window.location.search);this.docId=t.get("docId")??null,this.docId&&(this.ws=new WebSocket(this.options.serverUrl),this.ws.onopen=()=>{var e,o;console.log("WebSocket connected"),this.updateConnectionStatus("Connected"),(o=this.ws)==null||o.send(JSON.stringify({type:"join",docId:this.docId,userId:this.userId,content:(e=this.editor)==null?void 0:e.getHtml()}))},this.ws.onmessage=e=>{var s;const o=JSON.parse(e.data);if(o.type==="init"||o.type==="update"){if(console.log("onmessage",o),o.userId===this.userId){console.log("Ignoring self update");return}if(!o.content||o.content===""){console.log("Ignoring empty version:",o.content);return}if(o.version&&o.version<this.contentVersion){console.log("Ignoring older version:",o.version);return}if(this.normalizeHtml(o.content)===this.normalizeHtml(this.lastContent)){console.log("Content is the same, ignoring update");return}this.isExternalUpdate=!0,(s=this.editor)==null||s.setHtml(o.content),this.lastContent=o.content,this.contentVersion=o.version,this.isExternalUpdate=!1}},this.ws.onerror=e=>{console.error("WebSocket error:",e),this.updateConnectionStatus("Connection error")},this.ws.onclose=()=>{console.log("WebSocket disconnected. Reconnecting..."),this.updateConnectionStatus("Reconnecting..."),setTimeout(()=>this.setupCollaboration(),3e3)},this.unsubscribeFromContentChange=this.editor.subscribeToContentChange(e=>{this.handleContentChange(e)}))}debounce(t,e){let o;return(...s)=>{o&&clearTimeout(o),o=setTimeout(()=>{t(...s)},e)}}handleContentChange(t){if(!t||this.isExternalUpdate)return;const e=this.normalizeHtml(t),o=this.normalizeHtml(this.lastContent);e!==o&&(console.log("Content changed, scheduling update"),this.lastContent=t,this.contentVersion+=1,this.debouncedSendUpdate(t))}normalizeHtml(t){return t.replace(/\s+/g," ").replace(/>\s+</g,"><").replace(/\s+</g,"<").replace(/>\s+/g,">").trim()}createCollaborationContent(){const t=a.createContainer("p-4"),e=r(),o=`${window.location.origin}${window.location.pathname}?docId=${e}`,s=a.createLink(o,o,"_blank");return t.appendChild(document.createTextNode("Share this link to collaborate: ")),t.appendChild(s),t}startCollaboration(){const t=r();window.location.href=`${window.location.origin}${window.location.pathname}?docId=${t}}`}destroy(){this.ws&&(this.ws.close(),this.ws=null),this.popup&&(this.popup.destroy(),this.popup=null),this.unsubscribeFromContentChange&&(this.unsubscribeFromContentChange(),this.unsubscribeFromContentChange=null),this.editor=null}}exports.CollaborationPlugin=p;