code-editor

added sessions support

5/12/2023 9:44:36 AM

Details

diff --git a/codeeditor-app/app.html b/codeeditor-app/app.html
index d803575..2a4fe52 100644
--- a/codeeditor-app/app.html
+++ b/codeeditor-app/app.html
@@ -2,12 +2,17 @@
     <div class="flex-shrink section top">
         <h1>code editor</h1>
         <window-control distribute=".code-editor-containers">
+            <window-control-connector style="display: none;" target=".menu-container" class="active">Sessions</window-control-connector>
             <window-control-connector target="code-editor-container[language='Javascript']" class="active">Javascript</window-control-connector>
             <window-control-connector target="code-editor-container[language='HTML']">HTML</window-control-connector>
             <window-control-connector target="code-editor-container[language='CSS']">CSS</window-control-connector>
         </window-control>
     </div>
     <div class="flex-dynamic">
+        <div class="menu menu-container" id="session-menu" style="display: none">
+            <resize-handle target=".menu-container" place="right" dir="horizontal"></resize-handle>
+            <session-list></session-list>
+        </div>
         <div class="code-editor-containers flex-vert">
             <code-editor-container language="Javascript" dir="vertical" class="first-visible last-visible">
             </code-editor-container>
diff --git a/codeeditor-app/boot.ts b/codeeditor-app/boot.ts
index b990417..8fd4372 100644
--- a/codeeditor-app/boot.ts
+++ b/codeeditor-app/boot.ts
@@ -12,6 +12,10 @@ import { JavascriptCodeEditor } from './elements/code-editor/javascript-code-edi
 import { HtmlCodeEditor } from './elements/code-editor/html-code-editor';
 import { CssCodeEditor } from './elements/code-editor/css-code-editor';
 import { setDynamicFlexListener } from '../shared/set-dynamic-flex-listener';
+import { SessionList } from './elements/session-list/session-list';
+import { SessionListItem } from './elements/session-list-item/session-list-item';
+import { LoadingSpinner } from './elements/loading-spinner/loading-spinner';
+import { isSessionPage } from '../shared/page';
 
 window.customElements.define('app-root', AppRoot);
 window.customElements.define('code-editor-container', CodeEditorContainer);
@@ -24,8 +28,23 @@ window.customElements.define('notification-bubble', NotificationBubble);
 window.customElements.define('resize-handle', ResizeHandle);
 window.customElements.define('window-control', WindowControl);
 window.customElements.define('window-control-connector', WindowControlConnector);
-
+window.customElements.define('session-list', SessionList);
+window.customElements.define('session-list-item', SessionListItem);
+window.customElements.define('loading-spinner', LoadingSpinner);
 
 document.body.innerHTML += bootHtml;
 
+if (isSessionPage()) {
+        var menuEle = document.getElementById("session-menu");
+        var containers = <HTMLElement>document.getElementsByClassName("code-editor-containers")[0];
+        var outputframe = <HTMLElement>document.getElementsByClassName("output-frame-container")[0];
+        var sessionMenuItem = <HTMLElement>document.querySelector("window-control-connector[target='.menu-container']");
+        if (menuEle) {
+            menuEle.style.display = "block";
+            sessionMenuItem.style.display = "inline";
+            containers.style.display = "none";
+            outputframe.style.display = "none";
+        }
+}
+
 setDynamicFlexListener();
diff --git a/codeeditor-app/elements/code-editor/code-editor.ts b/codeeditor-app/elements/code-editor/code-editor.ts
index 74ca11c..b7390c6 100644
--- a/codeeditor-app/elements/code-editor/code-editor.ts
+++ b/codeeditor-app/elements/code-editor/code-editor.ts
@@ -3,11 +3,14 @@ import './code-editor.less';
 import * as monaco from 'monaco-editor';
 import { OutputFrame } from "../output-frame/output-frame";
 import { debounceManager } from "../../../shared/ensure-debounce";
+import * as sessionApi from '../../../shared/session-api';
+import { isSessionPage } from "../../../shared/page";
 
 export class CodeEditor extends BaseElement {
 
     public input: string = "";
     public language: string = "";
+    public editor!: monaco.editor.IStandaloneCodeEditor;
 
     onInit(): void {
 
@@ -18,11 +21,12 @@ export class CodeEditor extends BaseElement {
 
         const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
 
-        var editor = monaco.editor.create(this, {
-            value: this.input,
+        this.editor = monaco.editor.create(this, {
+            value: isSessionPage() ? "" : this.input,
             language: this.language,
             automaticLayout: true,
             contextmenu: false,
+            readOnly: isSessionPage(),
             minimap: {
                 enabled: false
             },
@@ -31,19 +35,30 @@ export class CodeEditor extends BaseElement {
         });
 
         var debounce = debounceManager(1000);
-        editor.onDidChangeModelContent((e) => {
-            this.input = editor.getValue();
-            debounce.ensureDebounce(() => {
-                this.outputFrame.setContent(this.language, this.input);
-            });
+        this.editor.onDidChangeModelContent((e) => {
+            if (!isSessionPage()) {
+                this.input = this.editor.getValue();
+                debounce.ensureDebounce(() => {
+                    sessionApi.setSessionData(this.language, this.input);
+                    this.outputFrame.setContent(this.language, this.input);
+                });
+            }
         });
 
         this.waitFor(this.outputFrame, () => {
-            this.outputFrame.setContent(this.language, this.input);
+            this.outputFrame.setContent(this.language, isSessionPage() ? "" : this.input);
         });
 
     }
 
+    setInput(input: any) {
+        if (this.input !== input) {
+            this.input = input;
+            this.editor.setValue(input);
+            this.outputFrame.setContent(this.language, this.input);
+        }
+    }
+
     setInitInput(): string {
         return "";
     }
diff --git a/codeeditor-app/elements/code-editor-container/code-editor-container.ts b/codeeditor-app/elements/code-editor-container/code-editor-container.ts
index 665fbd4..ceee3e1 100644
--- a/codeeditor-app/elements/code-editor-container/code-editor-container.ts
+++ b/codeeditor-app/elements/code-editor-container/code-editor-container.ts
@@ -4,6 +4,7 @@ import { ResizeHandle } from "../resize-handle/resize-handle";
 import './code-editor-container.less';
 
 export class CodeEditorContainer extends BaseElement {
+    private codeEditor: CodeEditor | null = null;
     onInit(): void {
         var language = this.getAttribute("language");
         this.classList.add("flex-vert");
@@ -22,11 +23,15 @@ export class CodeEditorContainer extends BaseElement {
         this.appendChild(div);
     }
 
+    setInput(input: any) {
+        this.codeEditor?.setInput(input);
+    }
+
     createCodeEditor(language: string, expandDir: 'vertical' | 'horizontal') {
         var codeEditorContent = document.createElement("div");
         codeEditorContent.classList.add("code-editor-content");
-        var codeEditor = <CodeEditor>document.createElement(language + "-code-editor");
-        codeEditorContent.appendChild(codeEditor);
+        this.codeEditor = <CodeEditor>document.createElement(language + "-code-editor");
+        codeEditorContent.appendChild(this.codeEditor);
 
         var resizeHandle = <ResizeHandle>document.createElement("resize-handle");
         resizeHandle.setAttribute("dir", expandDir);
diff --git a/codeeditor-app/elements/loading-spinner/loading-spinner.less b/codeeditor-app/elements/loading-spinner/loading-spinner.less
new file mode 100644
index 0000000..715e310
--- /dev/null
+++ b/codeeditor-app/elements/loading-spinner/loading-spinner.less
@@ -0,0 +1,176 @@
+loading-spinner {
+    display: block;
+    position: relative;
+    margin: 0 auto;
+    top: 50%;
+    transform: translateY(-50%);
+    border-radius: 50%;
+    opacity: 0.3;
+}
+
+.infinity-1 {
+    width:90px;
+    height:14px;
+    background: 
+      radial-gradient(circle 7px at bottom, #fff 92%,#0000 ) 0 0,
+      radial-gradient(circle 7px at top   , #fff 92%,#0000 ) 0 100%;
+    background-size:calc(100%/4) 50%;
+    background-repeat:repeat-x;
+    animation:i1 1s infinite;
+  }
+  @keyframes i1 {
+      80%,100% {background-position: calc(100%/3) 0,calc(100%/-3) 100%}
+  }
+  
+  .infinity-2 {
+    width:90px;
+    height:14px;
+    background: 
+      conic-gradient(from 135deg at top   ,#fff 90deg,#0000 0) 0 0,
+      conic-gradient(from -45deg at bottom,#fff 90deg,#0000 0) 0 100%;
+    background-size:calc(100%/4) 50%;
+    background-repeat:repeat-x;
+    animation:i2 1s infinite;
+  }
+  @keyframes i2 {
+      80%,100% {background-position: calc(100%/3) 0,calc(100%/-3) 100%}
+  }
+  
+  .infinity-3 {
+    width:90px;
+    height:14px;
+    background: 
+      radial-gradient(circle 7px at bottom, #fff 92%,#0000 ) calc(100%/2) 0,
+      radial-gradient(circle 7px at top   , #fff 92%,#0000 ) calc(100%/2) 100%,
+      conic-gradient(from 135deg at top   ,#fff 90deg,#0000 0) 0 0,
+      conic-gradient(from -45deg at bottom,#fff 90deg,#0000 0) 0 100%;
+    background-size:calc(100%/2) 50%;
+    background-repeat:repeat-x;
+    animation:i3 3s infinite;
+  }
+  @keyframes i3 {
+      0%  {background-position: calc(100%/2) 0,calc(100%/2) 100%,0 0, 0 100%}
+      20%,
+      30% {background-position: calc(3*100%/4) 0,calc(100%/4) 100%,calc(100%/4) 0, calc(100%/-4) 100%}
+      45%,
+      55% {background-position: 100% 0,0 100%,calc(100%/2) 0, calc(100%/-2) 100%}
+      70%,
+      80% {background-position: calc(5*100%/4) 0,calc(100%/-4) 100%,calc(3*100%/4) 0, calc(3*100%/-4) 100%}
+      100%{background-position: calc(3*100%/2) 0,calc(100%/-2) 100%,100% 0, -100% 100%}
+  }
+  
+  .infinity-4 {
+    width:90px;
+    height:14px;
+    background: 
+      radial-gradient(circle closest-side, #fff 92%,#0000 ) calc(100%/-4) 0,
+      radial-gradient(circle closest-side, #fff 92%,#0000 ) calc(100%/4)  0;
+    background-size:calc(100%/2) 100%;
+    animation:i4 1.5s infinite;
+  }
+  @keyframes i4 {
+      0%   {background-position: calc(100%/-4) 0    ,calc(100%/4) 0}
+      50%  {background-position: calc(100%/-4) -14px,calc(100%/4) 14px}
+      100% {background-position: calc(100%/4)  -14px,calc(3*100%/4) 14px}
+  }
+  
+  .infinity-5 {
+    width:60px;
+    aspect-ratio:1;
+    --g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
+    background: 
+      var(--g),
+      var(--g) 10px 10px,
+      var(--g) 20px 20px;
+    background-size: 50% 50%;
+    animation:i5 1s infinite;
+  }
+  @keyframes i5 {
+      90%,100%  {background-position: -30px 30px,-20px 40px,-10px 50px} 
+  }
+  
+  .infinity-6 {
+    width:60px;
+    aspect-ratio:1;
+    --g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
+    background: var(--g), var(--g), var(--g);
+    background-size: 50% 50%;
+    animation:i6 1s infinite;
+  }
+  @keyframes i6 {
+     0%   {background-position:0    0   ,10px 10px,20px 20px} 
+     50%  {background-position:0    20px,10px 10px,20px 0   } 
+     100% {background-position:20px 20px,10px 10px,0    0   } 
+  }
+  
+  .infinity-7 {
+    width:60px;
+    aspect-ratio:1;
+    --g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
+    background: var(--g), var(--g), var(--g);
+    background-size: 50% 50%;
+    animation:i7 1s infinite;
+  }
+  @keyframes i7 {
+     0%   {background-position:0     0, 10px 10px, 20px 20px}
+     33%  {background-position:-30px 0, 10px 10px, 20px 20px}
+     66%  {background-position:-30px 0,-20px 10px, 20px 20px}
+     100% {background-position:-30px 0,-20px 10px,-10px 20px}
+  }
+  
+  .infinity-8 {
+    width:60px;
+    aspect-ratio:1;
+    --g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
+    background: var(--g), var(--g), var(--g);
+    background-size: 50% 50%;
+    animation:i8 1s infinite;
+  }
+  @keyframes i8 {
+     0%   {background-position:0     0, 10px 10px, 20px 20px}
+     33%  {background-position:-30px 0, 10px 10px, 20px 20px}
+     66%  {background-position:-30px 0, 10px 40px, 20px 20px}
+     100% {background-position:-30px 0, 10px 40px, 50px 20px}
+  }
+  
+  .infinity-9 {
+    width:60px;
+    aspect-ratio:1;
+    --g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
+    background: var(--g), var(--g), var(--g);
+    background-size: 50% 50%;
+    animation:i9 1s infinite;
+  }
+  @keyframes i9 {
+     0%   {background-position:0     0, 10px 10px, 20px 20px}
+     33%  {background-position:10px  10px}
+     66%  {background-position:0    20px,10px 10px,20px 0   }
+     100% {background-position:0     0, 10px 10px, 20px 20px}
+  }
+  
+  .infinity-10 {
+    width:60px;
+    display:flex;
+    align-items:flex-start;
+    aspect-ratio:1;
+  }
+  .infinity-10:before,
+  .infinity-10:after {
+    content:"";
+    flex:1;
+    aspect-ratio:1;
+    --g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
+    background: var(--g), var(--g), var(--g);
+    filter:drop-shadow(30px 30px 0 #fff);
+    animation:i10 1s infinite;
+  }
+  .infinity-10:after {
+    transform:scaleX(-1);
+  }
+  @keyframes i10 {
+     0%   {background-position:0     0, 10px 10px, 20px 20px}
+     33%  {background-position:10px  10px}
+     66%  {background-position:0    20px,10px 10px,20px 0   }
+     100% {background-position:0     0, 10px 10px, 20px 20px}
+  }
+  
\ No newline at end of file
diff --git a/codeeditor-app/elements/loading-spinner/loading-spinner.ts b/codeeditor-app/elements/loading-spinner/loading-spinner.ts
new file mode 100644
index 0000000..bd59f31
--- /dev/null
+++ b/codeeditor-app/elements/loading-spinner/loading-spinner.ts
@@ -0,0 +1,8 @@
+import { BaseElement } from '../../../shared/_base';
+import './loading-spinner.less';
+
+export class LoadingSpinner extends BaseElement {
+    onInit(): void {
+        this.classList.add("infinity-5");
+    }
+}
\ No newline at end of file
diff --git a/codeeditor-app/elements/resize-handle/resize-handle.less b/codeeditor-app/elements/resize-handle/resize-handle.less
index 78b4719..daae0bc 100644
--- a/codeeditor-app/elements/resize-handle/resize-handle.less
+++ b/codeeditor-app/elements/resize-handle/resize-handle.less
@@ -34,6 +34,13 @@ resize-handle[dir="vertical"][place='top'] {
     bottom: auto;
 }
 
+resize-handle[dir="horizontal"][place='right'] {
+    top: 0;
+    bottom: 0;
+    right: 0;
+    left: auto;
+}
+
 #fixed-resize-overlay {
     position: fixed;
     left: 0;
diff --git a/codeeditor-app/elements/session-list/session-list.less b/codeeditor-app/elements/session-list/session-list.less
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/codeeditor-app/elements/session-list/session-list.less
diff --git a/codeeditor-app/elements/session-list/session-list.ts b/codeeditor-app/elements/session-list/session-list.ts
new file mode 100644
index 0000000..090c041
--- /dev/null
+++ b/codeeditor-app/elements/session-list/session-list.ts
@@ -0,0 +1,49 @@
+import { BaseElement } from '../../../shared/_base';
+import './session-list.less';
+import * as sessionApi from '../../../shared/session-api';
+import { isSessionPage } from '../../../shared/page';
+
+export class SessionList extends BaseElement {
+    onInit(): void {
+
+        if (isSessionPage()) {
+            var loadingSpinner = document.createElement("loading-spinner");
+            this.appendChild(loadingSpinner);
+
+            this.setUpdate();
+
+            setInterval(() => {
+            this.setUpdate();
+            }, 5000);
+        }
+    }
+
+    setUpdate() {
+
+        sessionApi.getSessions((sessions) => {
+            var loadingSpinner = this.getElementsByTagName("loading-spinner")[0];
+
+            console.log(loadingSpinner);
+
+            if (loadingSpinner) {
+                this.removeChild(loadingSpinner);
+            }
+
+            for (let session of sessions) {
+                var exists = document.querySelector("session-list-item[sessionId='" + session.id + "']");
+
+                if (!exists) {
+                    var ele = document.createElement("session-list-item");
+                    ele.setAttribute("sessionId", session.id);
+                    ele.setAttribute("numberOfChanges", session.numberOfChanges);
+
+                    this.appendChild(ele);
+                }
+                else {
+                    exists.setAttribute("numberOfChanges", session.numberOfChanges);
+                    exists.getElementsByClassName("session-list-item-number-of-changes")[0].innerHTML = session.numberOfChanges;
+                }
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/codeeditor-app/elements/session-list-item/session-list-item.less b/codeeditor-app/elements/session-list-item/session-list-item.less
new file mode 100644
index 0000000..9995337
--- /dev/null
+++ b/codeeditor-app/elements/session-list-item/session-list-item.less
@@ -0,0 +1,33 @@
+session-list-item {
+    color: white;
+    padding: 10px;
+    display: block;
+    position: relative;
+    border-bottom: 1px solid grey;
+    cursor: pointer;
+}
+
+session-list-item.selected {
+    background-color: #1e1e1e;
+}
+
+.session-list-item-session-id::before {
+    content: "Session: ";
+}
+
+.session-list-item-session-id {
+    display: block;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.session-list-item-number-of-changes {
+    font-size: 12px;
+}
+
+.session-list-item-number-of-changes::before {
+    content: "Number of changes: ";
+    position: relative;
+    z-index: 0;
+}
\ No newline at end of file
diff --git a/codeeditor-app/elements/session-list-item/session-list-item.ts b/codeeditor-app/elements/session-list-item/session-list-item.ts
new file mode 100644
index 0000000..3549be3
--- /dev/null
+++ b/codeeditor-app/elements/session-list-item/session-list-item.ts
@@ -0,0 +1,108 @@
+import { BaseElement } from '../../../shared/_base';
+import { CodeEditorContainer } from '../code-editor-container/code-editor-container';
+import './session-list-item.less';
+import * as sessionApi from '../../../shared/session-api';
+
+export class SessionListItem extends BaseElement {
+    onInit(): void {
+        if (this.hasAttribute("sessionId")) {
+            var sessionIdEle = document.createElement("div");
+            sessionIdEle.classList.add("session-list-item-session-id");
+            sessionIdEle.innerHTML = this.getAttribute("sessionId")?.toString() ?? "";
+            this.appendChild(sessionIdEle);
+        }
+
+        if (this.hasAttribute("numberOfChanges")) {
+            var numberOfChangesEle = document.createElement("div");
+            numberOfChangesEle.classList.add("session-list-item-number-of-changes");
+            numberOfChangesEle.innerHTML = this.getAttribute("numberOfChanges")?.toString() ?? "";
+            this.appendChild(numberOfChangesEle);
+        }
+
+        this.addEventListener("click", (evt) => {
+            this.itemClicked();
+        });
+    }
+
+    private intervalHandle: number | null = null;
+    stopUpdate() {
+        this.classList.remove("selected");
+
+        if (this.intervalHandle) {
+            window.clearInterval(this.intervalHandle);
+            this.intervalHandle = null;
+        }
+    }
+
+    startUpdate() {
+        this.stopUpdate();
+
+        this.classList.add("selected");
+
+        this.intervalHandle = window.setInterval(this.updateInputs.bind(this), 1000);
+    }
+
+    updateInputs() {
+        var codeEditorHTMLContainer = <CodeEditorContainer>document.querySelector("code-editor-container[language='HTML']");
+        var codeEditorCSSContainer = <CodeEditorContainer>document.querySelector("code-editor-container[language='CSS']");
+        var codeEditorJavascriptContainer = <CodeEditorContainer>document.querySelector("code-editor-container[language='Javascript']");
+    
+        this.getSessionData((js, html, css) => {
+            codeEditorJavascriptContainer.setInput(js?.data ?? "");
+            codeEditorHTMLContainer.setInput(html?.data ?? "");
+            codeEditorCSSContainer.setInput(css?.data ?? "");
+        });
+
+    }
+
+    getSessionData(onGet: (javascript: any, html: any, css: any) => void) {
+        var lastJavascript: any | null = null;
+        var lastHtml: any | null = null;
+        var lastCSS: any | null = null;
+
+        sessionApi.getSessionData(this.getAttribute("sessionId")?.toString()?? "", (data) => {
+            for (var i = data.length - 1; i >= 0; i--) {
+                var dataPoint = data[i];
+                 if (!lastJavascript && dataPoint.type == 0) {
+                    lastJavascript = dataPoint;
+                 }
+                 else if (!lastHtml && dataPoint.type == 1) {
+                    lastHtml = dataPoint;
+                 }
+                 else if (!lastCSS && dataPoint.type == 2) {
+                    lastCSS = dataPoint;
+                 }
+            }
+
+            onGet(lastJavascript, lastHtml, lastCSS);
+        });
+    }
+
+    itemClicked() {
+        if (!this.intervalHandle) {
+            var containers = <HTMLElement>document.getElementsByClassName("code-editor-containers")[0];
+            var outputframe = <HTMLElement>document.getElementsByClassName("output-frame-container")[0];
+
+            containers.style.display = "block";
+            outputframe.style.display = "block";
+
+            var children = this.parentElement?.children;
+
+            if (children) {
+                for (let i = 0; i < children.length; i++) {
+                    const child = <SessionListItem>children[i];
+                    if (child != this) {
+                        child.stopUpdate();
+                    }
+                    else {
+                        child.startUpdate();
+                    }
+                }
+            }
+        }
+        else {
+            console.log("WOULD STOP!");
+            this.stopUpdate();
+        }
+    }
+}
\ No newline at end of file

shared/page.ts 7(+7 -0)

diff --git a/shared/page.ts b/shared/page.ts
new file mode 100644
index 0000000..cc222c0
--- /dev/null
+++ b/shared/page.ts
@@ -0,0 +1,7 @@
+export function isSessionPage() {
+    return document.URL.indexOf("/sessions") != -1;
+}
+
+export function isRootPage() {
+    return document.URL.indexOf("/sessions") == -1;
+}
\ No newline at end of file
diff --git a/shared/session-api.ts b/shared/session-api.ts
new file mode 100644
index 0000000..580e158
--- /dev/null
+++ b/shared/session-api.ts
@@ -0,0 +1,90 @@
+var apiUrl = "https://codeeditor-api.davidssoft.com/";
+
+function getSessionId() {
+    var localstorageSessionId = localStorage.getItem("sessionId");
+
+    if (!localstorageSessionId) {
+        return setNewSession();
+    }
+    else {
+        var expiration = localStorage.getItem("sessionIdExpiration");
+
+        if (expiration) {
+            var expirationDate = new Date(expiration);
+
+            if (dateDiff(expirationDate, new Date()) > 120) {
+                return setNewSession();
+            }
+            else {
+                localStorage.setItem("sessionIdExpiration", (new Date()).toString());
+                return localstorageSessionId;
+            }
+
+        }
+        else {
+            return setNewSession();
+        }
+    }
+}
+
+function setNewSession() {
+    var newSessionId = uuidv4();
+    localStorage.setItem("sessionIdExpiration", (new Date()).toString());
+    localStorage.setItem("sessionId", newSessionId);
+
+    return newSessionId;
+}
+
+function dateDiff(startTime: Date, endTime: Date) {
+    var difference = endTime.getTime() - startTime.getTime(); // This will give difference in milliseconds
+    var resultInMinutes = Math.round(difference / 60000);
+    return resultInMinutes;
+}
+
+function uuidv4() {
+    //@ts-ignore
+    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
+      (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
+    );
+  }
+
+export function getSessions(onGet: (sessions: any[]) => void) {
+    fetch(apiUrl + "session/all").then((res) => {
+        res.json().then((jsonRes) => {
+            onGet(jsonRes as any);
+        });
+    });
+}
+
+export function getSessionData(sessionId: string, onGet: (sessions: any[]) => void) {
+    fetch(apiUrl + "session/data/" + sessionId, { method: "GET" }).then((res) => {
+        res.json().then((jsonRes) => {
+            onGet(jsonRes as any);
+        });
+    });
+}
+
+export function setSessionData(language: string, input: any, onSet?: () => void) {
+    var type = 0;
+
+    if (language.toLowerCase() == "javascript") {
+        type = 0;
+    }
+    else if (language.toLowerCase() == "html") {
+        type = 1;
+    }
+    else if (language.toLowerCase() == "css") {
+        type = 2;
+    }
+
+    fetch(apiUrl + "session/set", { 
+        method: "POST", 
+        headers: {
+            "Content-Type": "application/json",
+        },
+        body: JSON.stringify({ sessionId: getSessionId(), timestamp: new Date(), type: type, data: input }) }).then((res) => {
+        if (onSet) {
+            onSet();
+        }
+    });
+}
\ No newline at end of file