runlab 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/app.js +180 -4
- package/dist/app/core/editor.js +15 -3
- package/dist/app/core/navbar.js +127 -8
- package/dist/app/fileExplorer/FileExplorer.js +108 -25
- package/dist/app/fileExplorer/Folder.js +1 -0
- package/dist/app/terminal/commands.js +117 -0
- package/dist/app/terminal/terminal.js +126 -0
- package/dist/index.js +42 -20
- package/package.json +1 -2
- package/dist/wasm/runlab.wasm +0 -0
- package/dist/wasm/wasm_exec.js +0 -575
package/dist/app/app.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createEditor } from "./core/editor.js";
|
|
2
2
|
import { createNavbar } from "./core/navbar.js";
|
|
3
3
|
import { FileExplorer } from "./fileExplorer/FileExplorer.js";
|
|
4
|
+
import { createTerminal } from "./terminal/terminal.js";
|
|
4
5
|
|
|
5
6
|
export function generateContainer(parentId,w,h) {
|
|
6
7
|
const container = document.createElement("div");
|
|
@@ -13,13 +14,50 @@ export function generateContainer(parentId,w,h) {
|
|
|
13
14
|
justifyContent: "center",
|
|
14
15
|
alignItems: "center",
|
|
15
16
|
overflow: "hidden"
|
|
16
|
-
});
|
|
17
|
+
});
|
|
17
18
|
document.getElementById(parentId).appendChild(container);
|
|
18
19
|
gridTemplate("runlab-container", w, h);
|
|
19
|
-
createNavbar("runlab-navbar");
|
|
20
20
|
createEditor("runlab-editor","");
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// View and Editor toggle
|
|
23
|
+
const editor = document.getElementById("runlab-editor");
|
|
24
|
+
const overlay = document.createElement("div");
|
|
25
|
+
overlay.id = "runlab-view";
|
|
26
|
+
Object.assign(overlay.style, {
|
|
27
|
+
position: "absolute",
|
|
28
|
+
inset: "0",
|
|
29
|
+
backgroundColor: "#303030"
|
|
30
|
+
});
|
|
31
|
+
editor.style.position = "relative";
|
|
32
|
+
editor.appendChild(overlay);
|
|
33
|
+
|
|
34
|
+
const viewContent = document.createElement("iframe");
|
|
35
|
+
viewContent.id = "runlab-view-content";
|
|
36
|
+
Object.assign(viewContent.style, {
|
|
37
|
+
width: "100%",
|
|
38
|
+
height: "100%",
|
|
39
|
+
border: "none",
|
|
40
|
+
backgroundColor: "rgba(255, 255, 255, 0.8)"
|
|
41
|
+
});
|
|
42
|
+
document.getElementById("runlab-view").appendChild(viewContent);
|
|
43
|
+
|
|
44
|
+
const fe = new FileExplorer("runlab-file-explorer");
|
|
45
|
+
const root = fe.getRoot();
|
|
46
|
+
setFileExplorerNode(fe);
|
|
47
|
+
createNavbar("runlab-navbar");
|
|
48
|
+
|
|
49
|
+
setEditorActive(false); // Start with editor off
|
|
50
|
+
|
|
51
|
+
// ===============================
|
|
52
|
+
|
|
53
|
+
createTerminal("runlab-terminal",root);
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function appendViewContent(codeReturned) {
|
|
58
|
+
const viewContent = document.getElementById("runlab-view-content");
|
|
59
|
+
viewContent.srcdoc = codeReturned;
|
|
60
|
+
|
|
23
61
|
}
|
|
24
62
|
|
|
25
63
|
function gridTemplate(parent) {
|
|
@@ -60,7 +98,10 @@ function gridTemplate(parent) {
|
|
|
60
98
|
Object.assign(editor.style, {
|
|
61
99
|
gridColumn: "2 / 3",
|
|
62
100
|
gridRow: "2 / 3", // linha logo após a navbar
|
|
63
|
-
border: "1px solid #09090b"
|
|
101
|
+
border: "1px solid #09090b",
|
|
102
|
+
width: "100%",
|
|
103
|
+
height: "100%",
|
|
104
|
+
overflow: "hidden"
|
|
64
105
|
});
|
|
65
106
|
|
|
66
107
|
// Right Bottom
|
|
@@ -69,6 +110,9 @@ function gridTemplate(parent) {
|
|
|
69
110
|
Object.assign(terminal.style, {
|
|
70
111
|
gridColumn: "2 / 3",
|
|
71
112
|
gridRow: "3 / 4", // última linha
|
|
113
|
+
width: "100%",
|
|
114
|
+
height: "100%",
|
|
115
|
+
overflow: "hidden",
|
|
72
116
|
border: "1px solid #09090b"
|
|
73
117
|
});
|
|
74
118
|
|
|
@@ -77,4 +121,136 @@ function gridTemplate(parent) {
|
|
|
77
121
|
grid.appendChild(editor);
|
|
78
122
|
grid.appendChild(terminal);
|
|
79
123
|
document.getElementById(parent).appendChild(grid);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function setViewActive(status = false){
|
|
127
|
+
|
|
128
|
+
const editorBtn = document.getElementById("runlab-editor-btn");
|
|
129
|
+
const viewBtn = document.getElementById("runlab-view-btn");
|
|
130
|
+
|
|
131
|
+
editorBtn.classList.remove("active");
|
|
132
|
+
viewBtn.classList.remove("active");
|
|
133
|
+
if(status){
|
|
134
|
+
viewBtn.classList.add("active");
|
|
135
|
+
}
|
|
136
|
+
if(!status){
|
|
137
|
+
editorBtn.classList.add("active");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
[editorBtn, viewBtn].forEach(b => {
|
|
141
|
+
b.style.background = "transparent";
|
|
142
|
+
b.style.color = "#000";
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if(status){
|
|
146
|
+
document.getElementById("runlab-view").style.display = "block";
|
|
147
|
+
viewBtn.style.background = "#303030";
|
|
148
|
+
viewBtn.style.color = "#fff";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!status){
|
|
152
|
+
document.getElementById("runlab-view").style.display = "none";
|
|
153
|
+
editorBtn.style.background = "#303030";
|
|
154
|
+
editorBtn.style.color = "#fff";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function setEditorActive(status = true){
|
|
159
|
+
const editorWarning = document.createElement("div");
|
|
160
|
+
editorWarning.id = "runlab-editor-warning";
|
|
161
|
+
Object.assign(editorWarning.style, {
|
|
162
|
+
position: "absolute",
|
|
163
|
+
inset: "0",
|
|
164
|
+
display: "flex",
|
|
165
|
+
flexDirection: "column",
|
|
166
|
+
justifyContent: "center",
|
|
167
|
+
alignItems: "center",
|
|
168
|
+
gap: "8px",
|
|
169
|
+
textAlign: "center",
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
//================================ SVG Warning Icon ================================
|
|
173
|
+
const warningImage = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
174
|
+
|
|
175
|
+
warningImage.setAttribute("viewBox", "0 0 128 128");
|
|
176
|
+
warningImage.setAttribute("width", "128");
|
|
177
|
+
warningImage.setAttribute("height", "128");
|
|
178
|
+
warningImage.setAttribute("fill", "none");
|
|
179
|
+
|
|
180
|
+
warningImage.innerHTML = `
|
|
181
|
+
<path
|
|
182
|
+
d="M24 8 H80 L104 32 V112 H24 Z M80 8 V32 H104"
|
|
183
|
+
stroke="currentColor"
|
|
184
|
+
stroke-width="4"
|
|
185
|
+
stroke-linejoin="round"
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
<rect x="40" y="44" rx="6" ry="6" width="20" height="4"
|
|
189
|
+
fill="currentColor" transform="rotate(-25 36 44)" />
|
|
190
|
+
<rect x="68" y="44" rx="6" ry="6" width="20" height="4"
|
|
191
|
+
fill="currentColor" transform="rotate(25 64 44)" />
|
|
192
|
+
|
|
193
|
+
<circle cx="50" cy="64" r="5" fill="currentColor" />
|
|
194
|
+
<circle cx="78" cy="64" r="5" fill="currentColor" />
|
|
195
|
+
|
|
196
|
+
<rect x="44" y="80" rx="6" ry="6" width="40" height="5"
|
|
197
|
+
fill="currentColor" />
|
|
198
|
+
`;
|
|
199
|
+
|
|
200
|
+
warningImage.style.color = "#aaa";
|
|
201
|
+
|
|
202
|
+
//================================ SVG Warning Text ================================
|
|
203
|
+
|
|
204
|
+
const warningText = document.createElement("p");
|
|
205
|
+
warningText.textContent = "No file selected.";
|
|
206
|
+
warningText.style.color = "#aaa";
|
|
207
|
+
warningText.style.fontSize = "0.9em";
|
|
208
|
+
warningText.style.margin = "0";
|
|
209
|
+
|
|
210
|
+
const warningText2 = document.createElement("p");
|
|
211
|
+
warningText2.textContent =
|
|
212
|
+
"Please create a file using right click on the file explorer at the left container and select it.";
|
|
213
|
+
warningText2.style.color = "#aaa";
|
|
214
|
+
warningText2.style.fontSize = "0.75em";
|
|
215
|
+
warningText2.style.margin = "0";
|
|
216
|
+
|
|
217
|
+
//====================================================================================
|
|
218
|
+
|
|
219
|
+
editorWarning.appendChild(warningImage);
|
|
220
|
+
editorWarning.appendChild(warningText);
|
|
221
|
+
editorWarning.appendChild(warningText2);
|
|
222
|
+
|
|
223
|
+
const editorCodeMirror = document.getElementsByClassName("cm-editor ͼ1 ͼ3 ͼ16")[0];
|
|
224
|
+
|
|
225
|
+
if(!status){
|
|
226
|
+
document.getElementById("runlab-editor").appendChild(editorWarning);
|
|
227
|
+
if(editorCodeMirror){
|
|
228
|
+
editorCodeMirror.display = "none";
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if(status){
|
|
233
|
+
const existingWarning = document.getElementById("runlab-editor-warning");
|
|
234
|
+
if(existingWarning){
|
|
235
|
+
existingWarning.remove();
|
|
236
|
+
}
|
|
237
|
+
if(editorCodeMirror){
|
|
238
|
+
editorCodeMirror.display = "block";
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let feNode = null;
|
|
245
|
+
|
|
246
|
+
function setFileExplorerNode(node) {
|
|
247
|
+
feNode = node;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function getFeExecutables() {
|
|
251
|
+
return feNode.getExecutables()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function getFileNode(file) {
|
|
255
|
+
return feNode.getFileNode(file);
|
|
80
256
|
}
|
package/dist/app/core/editor.js
CHANGED
|
@@ -11,7 +11,6 @@ import { json } from "@codemirror/lang-json";
|
|
|
11
11
|
import { markdown } from "@codemirror/lang-markdown";
|
|
12
12
|
import { xml } from "@codemirror/lang-xml";
|
|
13
13
|
import { yaml } from "@codemirror/lang-yaml";
|
|
14
|
-
import { go } from "@codemirror/lang-go";
|
|
15
14
|
|
|
16
15
|
// VS Code look & feel
|
|
17
16
|
import { vscodeDark } from "@uiw/codemirror-theme-vscode";
|
|
@@ -29,12 +28,26 @@ export const languageCompartment = new Compartment();
|
|
|
29
28
|
|
|
30
29
|
export function setActiveFile(file) {
|
|
31
30
|
activeFile = file;
|
|
31
|
+
let navbarFileName = document.getElementById("runlab-navbar-active-file-name")
|
|
32
|
+
if (navbarFileName) {
|
|
33
|
+
navbarFileName.textContent = file ? `${file.name}.${file.ext}` : "";
|
|
34
|
+
}
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
function getActiveFile() {
|
|
35
38
|
return activeFile;
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
export function getCurrentCode() {
|
|
42
|
+
const activeFile = getActiveFile();
|
|
43
|
+
return activeFile ? activeFile.content : "";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getCurrentExtension() {
|
|
47
|
+
const activeFile = getActiveFile();
|
|
48
|
+
return activeFile ? activeFile.ext : "";
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
export function languageFromExtension(ext) {
|
|
39
52
|
switch (ext) {
|
|
40
53
|
case "txt": return [];
|
|
@@ -48,12 +61,11 @@ export function languageFromExtension(ext) {
|
|
|
48
61
|
case "css":return css();
|
|
49
62
|
case "js":return javascript({ typescript: false });
|
|
50
63
|
case "ts":return javascript({ typescript: true });
|
|
51
|
-
case "
|
|
64
|
+
case "lua":return [];
|
|
52
65
|
default:return [];
|
|
53
66
|
}
|
|
54
67
|
}
|
|
55
68
|
|
|
56
|
-
|
|
57
69
|
export function createEditor(parentId, initialCode = "") {
|
|
58
70
|
const parent = document.getElementById(parentId);
|
|
59
71
|
if (!parent) throw new Error(`Elemento #${parentId} não encontrado`);
|
package/dist/app/core/navbar.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { sendCode } from "../../index.js";
|
|
2
|
+
import { setViewActive } from "../app.js";
|
|
3
|
+
import { getCurrentCode, getCurrentExtension } from "./editor.js";
|
|
4
|
+
import Swal from "sweetalert2";
|
|
2
5
|
|
|
3
6
|
export function createNavbar(parentId) {
|
|
4
7
|
const navbar = document.createElement("nav");
|
|
@@ -8,28 +11,144 @@ export function createNavbar(parentId) {
|
|
|
8
11
|
height: "100%"
|
|
9
12
|
});
|
|
10
13
|
|
|
14
|
+
// ========== Menu Items ==========
|
|
15
|
+
|
|
11
16
|
const ul = document.createElement("ul");
|
|
12
17
|
Object.assign(ul.style, {
|
|
13
18
|
listStyleType: "none",
|
|
14
19
|
margin: "0",
|
|
15
20
|
padding: "0",
|
|
16
|
-
display: "flex"
|
|
21
|
+
display: "flex",
|
|
22
|
+
alignItems: "center",
|
|
23
|
+
width: "100%"
|
|
17
24
|
});
|
|
18
25
|
navbar.appendChild(ul);
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
|
|
28
|
+
// ========== Left Menu Items ==========
|
|
29
|
+
|
|
30
|
+
const leftGroup = document.createElement("div");
|
|
31
|
+
Object.assign(leftGroup.style, {
|
|
32
|
+
display: "flex",
|
|
33
|
+
alignItems: "center"
|
|
34
|
+
});
|
|
35
|
+
ul.appendChild(leftGroup);
|
|
36
|
+
|
|
37
|
+
const menuItems = ["Run", "Help"];
|
|
21
38
|
menuItems.forEach(item => {
|
|
22
|
-
|
|
39
|
+
const li = document.createElement("li");
|
|
23
40
|
li.textContent = item;
|
|
24
|
-
|
|
41
|
+
|
|
25
42
|
Object.assign(li.style, {
|
|
26
|
-
marginRight: "
|
|
43
|
+
marginRight: "15px",
|
|
44
|
+
marginLeft: "15px",
|
|
27
45
|
padding: "10px 14px",
|
|
28
46
|
cursor: "pointer",
|
|
29
|
-
color: "#fff"
|
|
30
|
-
textDecoration: "none"
|
|
47
|
+
color: "#fff"
|
|
31
48
|
});
|
|
49
|
+
if (item === "Run") {
|
|
50
|
+
li.addEventListener("click", () => {
|
|
51
|
+
sendCode(getCurrentCode(),getCurrentExtension());
|
|
52
|
+
setViewActive(true);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (item === "Help") {
|
|
56
|
+
li.addEventListener("click", () => {
|
|
57
|
+
Swal.fire({
|
|
58
|
+
title: "RunLab Help",
|
|
59
|
+
html: `
|
|
60
|
+
<p>RunLab is a web-based code editor and runtime environment.</p>
|
|
61
|
+
<p>Here's how to use it:</p>
|
|
62
|
+
<ul style="text-align: left;">
|
|
63
|
+
<li><strong>File Explorer:</strong> Use the file explorer to create, open, and manage your project files. Start it by right clicking on the left container.</li>
|
|
64
|
+
<li><strong>Editor:</strong> Write your code in the editor pane. It supports multiple file types. To use it you should click on a file.</li>
|
|
65
|
+
<li><strong>View:</strong> After writing your code, click the "Run" button in the navbar to execute it. The output will be displayed in the view pane.</li>
|
|
66
|
+
<li><strong>Terminal:</strong> You can run terminal commands in the terminal pane.</li>
|
|
67
|
+
</ul>
|
|
68
|
+
<p>Available terminal commands:</p>
|
|
69
|
+
<ul style="text-align: left;">
|
|
70
|
+
<li><span style="font-weight: bold;">ls</span>: List directory contents</li>
|
|
71
|
+
<li><span style="font-weight: bold;">cd</span>: Change directory</li>
|
|
72
|
+
<li><span style="font-weight: bold;">clear</span>: Clear the terminal</li>
|
|
73
|
+
<li><span style="font-weight: bold;">pwd</span>: Print current directory</li>
|
|
74
|
+
<li><span style="font-weight: bold;">run</span>: Run a file (e.g., run script.js)</li>
|
|
75
|
+
<li><span style="font-weight: bold;">help | h</span>: Show help message</li>
|
|
76
|
+
</ul>
|
|
77
|
+
`,
|
|
78
|
+
width: 700,
|
|
79
|
+
confirmButtonText: "Got it!"
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
leftGroup.appendChild(li);
|
|
32
85
|
});
|
|
33
86
|
|
|
87
|
+
// ========== Append navbar ==========
|
|
88
|
+
|
|
34
89
|
document.getElementById(parentId).appendChild(navbar);
|
|
90
|
+
|
|
91
|
+
// ========== ActiveFile Name ==========
|
|
92
|
+
const activeFileName = document.createElement("li");
|
|
93
|
+
activeFileName.id = "runlab-navbar-active-file-name";
|
|
94
|
+
|
|
95
|
+
Object.assign(activeFileName.style, {
|
|
96
|
+
margin: "0 auto",
|
|
97
|
+
padding: "10px 14px",
|
|
98
|
+
fontWeight: "600",
|
|
99
|
+
color: "#FFDE21",
|
|
100
|
+
whiteSpace: "nowrap"
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
ul.appendChild(activeFileName);
|
|
104
|
+
// ========== Editor/View Toggle ==========
|
|
105
|
+
|
|
106
|
+
const toggleLi = document.createElement("li");
|
|
107
|
+
Object.assign(toggleLi.style, {
|
|
108
|
+
|
|
109
|
+
padding: "4px 10px"
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const toggle = document.createElement("div");
|
|
113
|
+
Object.assign(toggle.style, {
|
|
114
|
+
display: "grid",
|
|
115
|
+
gridTemplateColumns: "1fr 1fr",
|
|
116
|
+
width: "180px",
|
|
117
|
+
height: "28px",
|
|
118
|
+
border: "2px solid #09090b",
|
|
119
|
+
borderRadius: "8px",
|
|
120
|
+
overflow: "hidden",
|
|
121
|
+
background: "#e5e7eb",
|
|
122
|
+
fontFamily: "sans-serif",
|
|
123
|
+
marginLeft: "20px"
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const editorBtn = document.createElement("button");
|
|
127
|
+
editorBtn.id = "runlab-editor-btn";
|
|
128
|
+
editorBtn.textContent = "Editor";
|
|
129
|
+
editorBtn.classList.add("active");
|
|
130
|
+
|
|
131
|
+
const viewBtn = document.createElement("button");
|
|
132
|
+
viewBtn.id = "runlab-view-btn";
|
|
133
|
+
viewBtn.textContent = "View";
|
|
134
|
+
|
|
135
|
+
[editorBtn, viewBtn].forEach(btn => {
|
|
136
|
+
Object.assign(btn.style, {
|
|
137
|
+
border: "none",
|
|
138
|
+
cursor: "pointer",
|
|
139
|
+
fontWeight: "500",
|
|
140
|
+
transition: "0.2s",
|
|
141
|
+
color: "#000"
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
toggle.append(editorBtn, viewBtn);
|
|
146
|
+
toggleLi.appendChild(toggle);
|
|
147
|
+
ul.appendChild(toggleLi);
|
|
148
|
+
|
|
149
|
+
//Initialize with editor active
|
|
150
|
+
setViewActive(false);
|
|
151
|
+
|
|
152
|
+
editorBtn.onclick = () => setViewActive(false);
|
|
153
|
+
viewBtn.onclick = () => setViewActive(true);
|
|
35
154
|
}
|
|
@@ -2,15 +2,46 @@ import { Folder } from "./Folder.js";
|
|
|
2
2
|
import { File } from "./File.js";
|
|
3
3
|
import { updateEditorContentById, setActiveFile } from "../core/editor.js";
|
|
4
4
|
import Swal from "sweetalert2";
|
|
5
|
+
import { setEditorActive, setViewActive } from "../app.js";
|
|
5
6
|
|
|
6
7
|
export class FileExplorer {
|
|
7
8
|
constructor(parentId) {
|
|
8
9
|
this.container = document.getElementById(parentId);
|
|
9
10
|
this.root = new Folder("root", null);
|
|
10
|
-
|
|
11
|
+
this.execFiles = [];
|
|
12
|
+
this.filesPath = [];
|
|
13
|
+
this.path = [];
|
|
11
14
|
this.render();
|
|
12
15
|
}
|
|
13
16
|
|
|
17
|
+
getRoot() {
|
|
18
|
+
return this.root;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getFileNode(file) {
|
|
22
|
+
const name = file.name.split(".")[0];
|
|
23
|
+
const ext = file.name.split(".")[1];
|
|
24
|
+
const path = file.path;
|
|
25
|
+
let currentNode = this.root;
|
|
26
|
+
|
|
27
|
+
for (let i = 1; i < path.length; i++) {
|
|
28
|
+
const part = path[i];
|
|
29
|
+
const nextNode = currentNode.children.find(c => c.name === part && !c.ext);
|
|
30
|
+
if (!nextNode) return null;
|
|
31
|
+
currentNode = nextNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return currentNode.children.find(c => c.name === name && c.ext === ext);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getExecutables() {
|
|
38
|
+
return this.execFiles;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setExecutables(files) {
|
|
42
|
+
this.execFiles = files;
|
|
43
|
+
}
|
|
44
|
+
|
|
14
45
|
/* =========================
|
|
15
46
|
RENDER
|
|
16
47
|
========================== */
|
|
@@ -50,12 +81,17 @@ export class FileExplorer {
|
|
|
50
81
|
btn.style.paddingBottom = "8px";
|
|
51
82
|
btn.style.cursor = "pointer";
|
|
52
83
|
|
|
84
|
+
|
|
53
85
|
|
|
54
86
|
btn.onmouseover = () => btn.style.backgroundColor = "#555";
|
|
55
87
|
btn.onmouseout = () => btn.style.backgroundColor = "transparent";
|
|
56
88
|
|
|
57
89
|
const ul = document.createElement("ul");
|
|
58
90
|
ul.style.display = "none";
|
|
91
|
+
ul.style.listStyle = "none";
|
|
92
|
+
ul.style.margin = "0";
|
|
93
|
+
ul.style.padding = "0 0 0 24px";
|
|
94
|
+
|
|
59
95
|
|
|
60
96
|
btn.onclick = () => this.toggle(ul);
|
|
61
97
|
btn.oncontextmenu = e => {
|
|
@@ -79,9 +115,12 @@ export class FileExplorer {
|
|
|
79
115
|
li.style.paddingTop = "8px";
|
|
80
116
|
li.style.paddingBottom = "8px";
|
|
81
117
|
li.style.cursor = "pointer";
|
|
118
|
+
|
|
82
119
|
|
|
83
120
|
li.onclick = () => {
|
|
84
121
|
setActiveFile(node);
|
|
122
|
+
setViewActive(false);
|
|
123
|
+
setEditorActive(true);
|
|
85
124
|
updateEditorContentById("runlab-editor", node.content);
|
|
86
125
|
};
|
|
87
126
|
|
|
@@ -92,8 +131,12 @@ export class FileExplorer {
|
|
|
92
131
|
};
|
|
93
132
|
|
|
94
133
|
parentUl.appendChild(li);
|
|
134
|
+
this.filesPath.push({ name: `${node.name}.${node.ext}`, path: node.parent.path });
|
|
135
|
+
|
|
95
136
|
}
|
|
96
137
|
});
|
|
138
|
+
|
|
139
|
+
this.setExecutables(this.filesPath);
|
|
97
140
|
}
|
|
98
141
|
|
|
99
142
|
toggle(el) {
|
|
@@ -138,6 +181,7 @@ export class FileExplorer {
|
|
|
138
181
|
input: 'text',
|
|
139
182
|
showCancelButton: true,
|
|
140
183
|
confirmButtonText: 'Create',
|
|
184
|
+
draggable: true,
|
|
141
185
|
preConfirm: (name) => {
|
|
142
186
|
if (name) {
|
|
143
187
|
this.addFolder(this.root, name);
|
|
@@ -151,20 +195,21 @@ export class FileExplorer {
|
|
|
151
195
|
title: 'Choose extension and filename',
|
|
152
196
|
html:
|
|
153
197
|
'<select id="swal-select" class="swal2-input">' +
|
|
154
|
-
'<option value="txt"
|
|
155
|
-
'<option value="md"
|
|
156
|
-
'<option value="json"
|
|
157
|
-
'<option value="yaml"
|
|
158
|
-
'<option value="toml"
|
|
159
|
-
'<option value="html"
|
|
160
|
-
'<option value="xml"
|
|
161
|
-
'<option value="css"
|
|
162
|
-
'<option value="js"
|
|
163
|
-
'<option value="ts"
|
|
164
|
-
'<option value="
|
|
198
|
+
'<option value="txt">📄 .txt - Text</option>' +
|
|
199
|
+
'<option value="md">📝 .md - Text</option>' +
|
|
200
|
+
'<option value="json">🧩 .json - Data</option>' +
|
|
201
|
+
'<option value="yaml">🧩 .yaml - Data</option>' +
|
|
202
|
+
'<option value="toml">🧩 .toml - Data</option>' +
|
|
203
|
+
'<option value="html">🌐 .html - Markup</option>' +
|
|
204
|
+
'<option value="xml">🌐 .xml - Markup</option>' +
|
|
205
|
+
'<option value="css">🎨 .css - Style</option>' +
|
|
206
|
+
'<option value="js">🟨 .js - JavaScript</option>' +
|
|
207
|
+
'<option value="ts">🟦 .ts - TypeScript</option>' +
|
|
208
|
+
'<option value="py">🐍 .py - Python</option>' +
|
|
165
209
|
'</select>' +
|
|
166
210
|
'<input id="swal-input" class="swal2-input" placeholder="filename">',
|
|
167
211
|
focusConfirm: false,
|
|
212
|
+
draggable: true,
|
|
168
213
|
preConfirm: () => {
|
|
169
214
|
return [
|
|
170
215
|
document.getElementById('swal-select').value,
|
|
@@ -177,10 +222,21 @@ export class FileExplorer {
|
|
|
177
222
|
this.addFile(this.root, text, selection);
|
|
178
223
|
}
|
|
179
224
|
})
|
|
180
|
-
}
|
|
225
|
+
}
|
|
181
226
|
]);
|
|
182
227
|
|
|
183
228
|
this.openMenu(e, menu);
|
|
229
|
+
|
|
230
|
+
const closeMenu = () => {
|
|
231
|
+
menu.remove();
|
|
232
|
+
document.removeEventListener("click", closeMenu);
|
|
233
|
+
document.removeEventListener("contextmenu", closeMenu);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
setTimeout(() => {
|
|
237
|
+
document.addEventListener("click", closeMenu);
|
|
238
|
+
document.addEventListener("contextmenu", closeMenu);
|
|
239
|
+
});
|
|
184
240
|
}
|
|
185
241
|
|
|
186
242
|
showFolderMenu(e, folder) {
|
|
@@ -190,6 +246,7 @@ export class FileExplorer {
|
|
|
190
246
|
input: 'text',
|
|
191
247
|
showCancelButton: true,
|
|
192
248
|
confirmButtonText: 'Create',
|
|
249
|
+
draggable: true,
|
|
193
250
|
preConfirm: (name) => {
|
|
194
251
|
if (name) {
|
|
195
252
|
this.addFolder(folder, name);
|
|
@@ -200,20 +257,21 @@ export class FileExplorer {
|
|
|
200
257
|
title: 'Choose extension and filename',
|
|
201
258
|
html:
|
|
202
259
|
'<select id="swal-select" class="swal2-input">' +
|
|
203
|
-
'<option value="txt"
|
|
204
|
-
'<option value="md"
|
|
205
|
-
'<option value="json"
|
|
206
|
-
'<option value="yaml"
|
|
207
|
-
'<option value="toml"
|
|
208
|
-
'<option value="html"
|
|
209
|
-
'<option value="xml"
|
|
210
|
-
'<option value="css"
|
|
211
|
-
'<option value="js"
|
|
212
|
-
'<option value="ts"
|
|
213
|
-
'<option value="
|
|
260
|
+
'<option value="txt">📄 .txt - Text</option>' +
|
|
261
|
+
'<option value="md">📝 .md - Text</option>' +
|
|
262
|
+
'<option value="json">🧩 .json - Data</option>' +
|
|
263
|
+
'<option value="yaml">🧩 .yaml - Data</option>' +
|
|
264
|
+
'<option value="toml">🧩 .toml - Data</option>' +
|
|
265
|
+
'<option value="html">🌐 .html - Markup</option>' +
|
|
266
|
+
'<option value="xml">🌐 .xml - Markup</option>' +
|
|
267
|
+
'<option value="css">🎨 .css - Style</option>' +
|
|
268
|
+
'<option value="js">🟨 .js - JavaScript</option>' +
|
|
269
|
+
'<option value="ts">🟦 .ts - TypeScript</option>' +
|
|
270
|
+
'<option value="py">🐍 .py - Python</option>' +
|
|
214
271
|
'</select>' +
|
|
215
272
|
'<input id="swal-input" class="swal2-input" placeholder="filename">',
|
|
216
273
|
focusConfirm: false,
|
|
274
|
+
draggable: true,
|
|
217
275
|
preConfirm: () => {
|
|
218
276
|
return [
|
|
219
277
|
document.getElementById('swal-select').value,
|
|
@@ -223,7 +281,7 @@ export class FileExplorer {
|
|
|
223
281
|
}).then((result) => {
|
|
224
282
|
if (result.value) {
|
|
225
283
|
const [selection, text] = result.value;
|
|
226
|
-
this.addFile(
|
|
284
|
+
this.addFile(folder, text, selection);
|
|
227
285
|
}
|
|
228
286
|
})
|
|
229
287
|
},
|
|
@@ -232,6 +290,7 @@ export class FileExplorer {
|
|
|
232
290
|
input: 'text',
|
|
233
291
|
showCancelButton: true,
|
|
234
292
|
confirmButtonText: 'Rename',
|
|
293
|
+
draggable: true,
|
|
235
294
|
preConfirm: (name) => {
|
|
236
295
|
if (name) {
|
|
237
296
|
this.rename(folder, name);
|
|
@@ -242,6 +301,17 @@ export class FileExplorer {
|
|
|
242
301
|
]);
|
|
243
302
|
|
|
244
303
|
this.openMenu(e, menu);
|
|
304
|
+
|
|
305
|
+
const closeMenu = () => {
|
|
306
|
+
menu.remove();
|
|
307
|
+
document.removeEventListener("click", closeMenu);
|
|
308
|
+
document.removeEventListener("contextmenu", closeMenu);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
setTimeout(() => {
|
|
312
|
+
document.addEventListener("click", closeMenu);
|
|
313
|
+
document.addEventListener("contextmenu", closeMenu);
|
|
314
|
+
});
|
|
245
315
|
}
|
|
246
316
|
|
|
247
317
|
showFileMenu(e, file) {
|
|
@@ -251,6 +321,7 @@ export class FileExplorer {
|
|
|
251
321
|
input: 'text',
|
|
252
322
|
showCancelButton: true,
|
|
253
323
|
confirmButtonText: 'Rename',
|
|
324
|
+
draggable: true,
|
|
254
325
|
preConfirm: (name) => {
|
|
255
326
|
if (name) {
|
|
256
327
|
this.rename(file, name);
|
|
@@ -261,6 +332,7 @@ export class FileExplorer {
|
|
|
261
332
|
title: '',
|
|
262
333
|
showCancelButton: true,
|
|
263
334
|
confirmButtonText: 'Delete',
|
|
335
|
+
draggable: true,
|
|
264
336
|
preConfirm: (name) => {
|
|
265
337
|
if (name) {
|
|
266
338
|
this.delete(file);
|
|
@@ -270,6 +342,17 @@ export class FileExplorer {
|
|
|
270
342
|
]);
|
|
271
343
|
|
|
272
344
|
this.openMenu(e, menu);
|
|
345
|
+
|
|
346
|
+
const closeMenu = () => {
|
|
347
|
+
menu.remove();
|
|
348
|
+
document.removeEventListener("click", closeMenu);
|
|
349
|
+
document.removeEventListener("contextmenu", closeMenu);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
setTimeout(() => {
|
|
353
|
+
document.addEventListener("click", closeMenu);
|
|
354
|
+
document.addEventListener("contextmenu", closeMenu);
|
|
355
|
+
});
|
|
273
356
|
}
|
|
274
357
|
|
|
275
358
|
/* =========================
|