From 1e1bd4058ad1189a83ad225c8aa166f27a9f917d Mon Sep 17 00:00:00 2001
From: Max <m.giller@tu-bs.de>
Date: Wed, 27 Apr 2022 10:31:53 +0200
Subject: [PATCH] Connected first components to editor backend, but still WIP

---
 src/backend.js                                |   2 +
 src/backend.tsx                               |   8 ++
 src/editor/editor.php                         | 119 +-----------------
 src/editor/js/components/editor.tsx           |  52 ++++++++
 src/editor/js/components/toolbar.tsx          |  12 ++
 src/editor/js/components/toolitem.tsx         |  44 +++++++
 src/editor/js/graph.js                        |  34 -----
 src/editor/js/structures/editor/tools/tool.ts |   7 ++
 src/editor/js/structures/graph/graph.ts       |  24 ++++
 webpack.common.js                             |   2 +-
 10 files changed, 151 insertions(+), 153 deletions(-)
 create mode 100644 src/backend.tsx
 create mode 100644 src/editor/js/components/editor.tsx
 create mode 100644 src/editor/js/components/toolbar.tsx
 create mode 100644 src/editor/js/components/toolitem.tsx
 create mode 100644 src/editor/js/structures/editor/tools/tool.ts

diff --git a/src/backend.js b/src/backend.js
index fe9e170..3aefed2 100644
--- a/src/backend.js
+++ b/src/backend.js
@@ -3,3 +3,5 @@ import "./editor/css/editor.css";
 
 import "./display/display";
 import "./editor/js/editor";
+
+// TODO: Is this file deprecated?
diff --git a/src/backend.tsx b/src/backend.tsx
new file mode 100644
index 0000000..8df5b72
--- /dev/null
+++ b/src/backend.tsx
@@ -0,0 +1,8 @@
+import React from "react";
+import ReactDOM from "react-dom";
+
+import "./editor/css/editor.css";
+import "./editor/js/editor";
+import { Editor } from "./editor/js/components/editor";
+
+ReactDOM.render(<Editor />, document.getElementById("ks-editor"));
diff --git a/src/editor/editor.php b/src/editor/editor.php
index cf25e16..944183b 100644
--- a/src/editor/editor.php
+++ b/src/editor/editor.php
@@ -1,118 +1 @@
-<div id="ks-editor">
-    <!--The id "ks-editor" indicates, that the javascript associated with this should automatically be executed-->
-    <h1>Interface</h1>
-    <div id="box-select-layer"><div id="2d-graph"></div></div>
-    <section id="toolbar"></section>
-    <section id="tool-menu">
-        <div id="delete-menu" class="hidden">
-            <p>Drag and drop while pressing SHIFT to delete all the nodes that are being selected.</p>
-        </div>
-        <div id="collect-menu" class="hidden">
-            <h3>Collected items</h3>
-            <button id="clear-collection">Clear</button>
-            <ul id="selected-items"></ul>
-        </div>
-        <div id="select-menu" class="">
-            <p id="nothing-selected">Nothing selected</p>
-            <div id="node-selected" class="hidden">
-                <label for="node-name" hidden>Name</label>
-                </br>
-                <input type="text" id="node-name" name="node-name" placeholder="Enter name" class="bottom-space"></input>
-
-                </br>
-
-                <label for="node-description">Description</label>
-                </br>
-                <textarea id="node-description" name="node-description" class="bottom-space"></textarea>
-
-                </br>
-                <label for="node-image">Node Image</label>
-                </br>
-                <img id="node-image-preview" style="color:red" class="preview-image" src="" />
-                </br>
-                <input type="text" id="node-image" name="node-image" placeholder="Enter file name or URL" class="bottom-space" />
-
-                </br>
-                <label for="node-detail-image">Info Image</label>
-                </br>
-                <img id="node-detail-image-preview" style="color:red" class="preview-image" src="" />
-                </br>
-                <input type="text" id="node-detail-image" name="node-detail-image" placeholder="Enter file name or URL" class="bottom-space" />
-
-                </br>
-                <label for="node-type">Type</label>
-                </br>
-                <select id="node-type" name="node-type" class="bottom-space">
-                    <option value="Vorlesung">Vorlesung</option>
-                    <option value="Algorithmus">Algorithmus</option>
-                    <option value="Definition">Definition</option>
-                    <option value="Beispiel">Beispiel</option>
-                    <option value="Ãœbung">Ãœbung</option>
-                    <option value="Kapitel">Kapitel</option>
-                </select>
-
-                </br>
-                <label for="node-video">Video</label>
-                </br>
-                <input type="text" placeholder="Video URL" id="node-video" name="node-video"></input>
-
-                </br>
-                <label for="node-references">References</label> <small>One URL per line</small>
-                </br>
-                <textarea id="node-references" name="node-references" class="bottom-space"></textarea>
-            </div>
-            <div id="link-selected" class="hidden">
-                <h3 id="link-name"></h3>
-            </div>
-        </div>
-        <div id="settings-menu" class="hidden" checked>
-            <label for="label-toggle" class="bottom-space">
-                <input type="checkbox" checked id="label-toggle" name="label-toggle"></input>
-                Show labels in graph
-            </label>
-            </br>
-            </br>
-
-
-            <h3>Space</h3>
-            <label for="space-id-select">Currently open</label>
-            </br>
-            <select id="space-id-select" name="space-id-select" class="bottom-space">
-            </select>
-
-            </br>
-            </br>
-
-            <h3>Physics Simulation</h3>
-
-            <button id="reanimate-button" name="reanimate-button" class="bottom-space">Re-simulate</button>
-
-            </br>
-
-            <label for="stop-physics-delay">Amount of time [in seconds] after which the physics simulation is stopped</label>
-            </br>
-            <input type="number" onkeypress="return (event.charCode !=8 && event.charCode ==0 || (event.charCode >= 48 && event.charCode <= 57))" value="5" id="stop-physics-delay" name="stop-physics-delay" class="small-width">
-            </input>
-            </br>
-            </br>
-
-
-            <h3>Import Space</h3>
-            <label for="import-space-area">Space JSON</label>
-            </br>
-            <textarea id="import-space-area" name="import-space-area" class="bottom-space">
-            </textarea>
-            </br>
-            <label for="import-space-name-text">Space Name</label>
-            </br>
-            <input type="text" id="import-space-name-text" name="import-space-name-text" class="bottom-space">
-            </input>
-            </br>
-            <button id="import-space-btn" name="import-space-btn" class="bottom-space">Import</button>
-
-            </br>
-            </br>
-
-        </div>
-    </section>
-</div>
\ No newline at end of file
+<div id="ks-editor"></div>
\ No newline at end of file
diff --git a/src/editor/js/components/editor.tsx b/src/editor/js/components/editor.tsx
new file mode 100644
index 0000000..7e52996
--- /dev/null
+++ b/src/editor/js/components/editor.tsx
@@ -0,0 +1,52 @@
+import React from "react";
+import { Tool } from "../structures/editor/tools/tool";
+import { ToolBar } from "./toolbar";
+
+export class Editor extends React.Component {
+    state: {
+        currentTool: Tool;
+        previousTool: Tool;
+    };
+
+    constructor(props: any) {
+        super(props);
+    }
+
+    /**
+     * Sets current tool. Select events not triggered if already selected.
+     * @param tool New tool to select.
+     */
+    public setTool(tool: Tool) {
+        if (this.state.currentTool == tool) {
+            return;
+        }
+
+        this.setState({ currentTool: tool });
+    }
+
+    /**
+     * If exists, sets previously selected tool as current tool.
+     */
+    public setPreviousTool() {
+        if (this.state.previousTool === undefined) {
+            return;
+        }
+
+        this.setTool(this.state.previousTool);
+    }
+
+    /**
+     * @returns Tool that is currently selected.
+     */
+    public getCurrentTool(): Tool {
+        return this.state.currentTool;
+    }
+
+    render(): React.ReactNode {
+        return (
+            <div id="ks-editor">
+                <ToolBar editor={this}></ToolBar>
+            </div>
+        );
+    }
+}
diff --git a/src/editor/js/components/toolbar.tsx b/src/editor/js/components/toolbar.tsx
new file mode 100644
index 0000000..ad08e59
--- /dev/null
+++ b/src/editor/js/components/toolbar.tsx
@@ -0,0 +1,12 @@
+import React from "react";
+import { Editor } from "./editor";
+
+type ToolBarProps = { editor: Editor };
+
+export class ToolBar extends React.Component {
+    props: ToolBarProps;
+
+    constructor(props: ToolBarProps) {
+        super(props);
+    }
+}
diff --git a/src/editor/js/components/toolitem.tsx b/src/editor/js/components/toolitem.tsx
new file mode 100644
index 0000000..b590060
--- /dev/null
+++ b/src/editor/js/components/toolitem.tsx
@@ -0,0 +1,44 @@
+import React from "react";
+import { Tool } from "../structures/editor/tools/tool";
+import { Editor } from "./editor";
+
+type ToolItemProps = { tool: Tool; editor: Editor };
+
+class ToolItem extends React.Component {
+    state = {};
+    props: ToolItemProps;
+
+    constructor(props: ToolItemProps) {
+        super(props);
+    }
+
+    /**
+     * Handles the click-on-tool-icon event.
+     */
+    private handleClick() {
+        if (this.props.editor.getCurrentTool() !== this.props.tool) {
+            // Not selected, so select
+            this.props.editor.setTool(this.props.tool);
+            return;
+        }
+
+        // Is already set, so only unset, if tool is toggleable
+        if (!this.props.tool.isToggleable) {
+            return;
+        }
+
+        this.props.editor.setPreviousTool();
+    }
+
+    public render() {
+        return (
+            <button
+                id={this.props.tool.id}
+                title={this.props.tool.name}
+                onClick={this.handleClick}
+            >
+                <img src={this.props.tool.icon} />
+            </button>
+        );
+    }
+}
diff --git a/src/editor/js/graph.js b/src/editor/js/graph.js
index 68e52e8..81c1e42 100644
--- a/src/editor/js/graph.js
+++ b/src/editor/js/graph.js
@@ -86,40 +86,6 @@ export class PREVIOUSGraph extends ManagedData {
         return cleanLink;
     }
 
-    existsNodeId(nodeId) {
-        var nodes = this.data[GRAPH_NODES];
-        for (var i = 0; i < nodes.length; i++) {
-            if (nodes[i][NODE_ID] === nodeId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    getUnusedNodeId() {
-        var id;
-        do {
-            id = this.getRandomString();
-        } while (this.existsNodeId(id));
-        return id;
-    }
-
-    getRandomString(length = 8) {
-        // Move to global helpers
-        // Based on: https://stackoverflow.com/a/1349426/7376120
-        var characters =
-            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-        var charactersLength = characters.length;
-
-        var result = "";
-        for (var i = 0; i < length; i++) {
-            result += characters.charAt(
-                Math.floor(Math.random() * charactersLength)
-            );
-        }
-        return result;
-    }
-
     static toStr(item) {
         if (item === undefined) {
             return "UNDEFINED";
diff --git a/src/editor/js/structures/editor/tools/tool.ts b/src/editor/js/structures/editor/tools/tool.ts
new file mode 100644
index 0000000..c379e8f
--- /dev/null
+++ b/src/editor/js/structures/editor/tools/tool.ts
@@ -0,0 +1,7 @@
+export class Tool {
+    public id: string;
+    public name: string;
+    public icon: string;
+
+    public isToggleable: boolean = false;
+}
\ No newline at end of file
diff --git a/src/editor/js/structures/graph/graph.ts b/src/editor/js/structures/graph/graph.ts
index ccadd99..91b4648 100644
--- a/src/editor/js/structures/graph/graph.ts
+++ b/src/editor/js/structures/graph/graph.ts
@@ -26,6 +26,30 @@ export class Graph extends ManagedData {
 
         this.prepareIds(data);
     }
+    
+    /**
+     * Intuitive getter for links.
+     * @returns All links associated with the graph.
+     */
+    public get links(): Link[] {
+        return this.data.links;
+    }
+    
+    /**
+     * Intuitive getter for nodes.
+     * @returns All nodes associated with the graph.
+     */
+    public get nodes(): Node[] {
+        return this.data.nodes;
+    }
+    
+    /**
+     * Intuitive getter for node types.
+     * @returns All node types associated with the graph.
+     */
+    public get types(): NodeType[] {
+        return this.data.types;
+    }
 
     /**
      * Determines the highest, used ids for GraphElements in data for later use.
diff --git a/webpack.common.js b/webpack.common.js
index 543a79e..00a8982 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -9,7 +9,7 @@ const babelOptions = {
 module.exports = {
     entry: {
         frontend: "./src/frontend.tsx",
-        backend: "./src/backend.js",
+        backend: "./src/backend.tsx",
     },
     output: {
         filename: "[name].js",
-- 
GitLab