Spaces:
Running
Running
Update index.html
Browse files- index.html +29 -40
index.html
CHANGED
@@ -151,9 +151,7 @@
|
|
151 |
highestZ++;
|
152 |
node.style.zIndex = highestZ;
|
153 |
|
154 |
-
// Add a remove button inside the header
|
155 |
let html = `<div class="node-header">${type}<span class="remove-node" onclick="removeNode(this)">×</span></div>`;
|
156 |
-
// Node types and their inner HTML
|
157 |
if (type === 'Variable') {
|
158 |
html += `
|
159 |
<input type="text" class="var-name" placeholder="Variable Name">
|
@@ -168,7 +166,7 @@
|
|
168 |
`;
|
169 |
} else if (type === 'Print') {
|
170 |
html += `
|
171 |
-
<input type="text" class="print-value" placeholder="
|
172 |
<div class="port port-input" data-type="input"></div>
|
173 |
`;
|
174 |
} else if (type === 'Function') {
|
@@ -228,7 +226,8 @@
|
|
228 |
`;
|
229 |
} else if (type === 'Break' || type === 'Continue') {
|
230 |
html += `<div class="port port-input" data-type="input"></div>`;
|
231 |
-
} else if (type === 'Add' || type === 'Subtract' ||
|
|
|
232 |
html += `
|
233 |
<input type="text" class="operand1" placeholder="Operand 1">
|
234 |
<input type="text" class="operand2" placeholder="Operand 2">
|
@@ -303,7 +302,6 @@
|
|
303 |
// ----------------------------
|
304 |
function removeNode(removeButton) {
|
305 |
const node = removeButton.parentElement.parentElement;
|
306 |
-
// Remove connections for this node
|
307 |
connections = connections.filter(conn => conn.from.parentElement !== node && conn.to.parentElement !== node);
|
308 |
node.remove();
|
309 |
nodes = nodes.filter(n => n !== node);
|
@@ -394,7 +392,6 @@
|
|
394 |
}
|
395 |
}
|
396 |
});
|
397 |
-
|
398 |
document.addEventListener('mouseup', (e) => {
|
399 |
if (draggingNode) draggingNode = null;
|
400 |
if (draggingPort) {
|
@@ -413,7 +410,6 @@
|
|
413 |
}
|
414 |
}
|
415 |
});
|
416 |
-
|
417 |
function updateConnections() {
|
418 |
connectionsSvg.innerHTML = '';
|
419 |
const canvasRect = canvas.getBoundingClientRect();
|
@@ -433,14 +429,19 @@
|
|
433 |
}
|
434 |
|
435 |
// ----------------------------
|
436 |
-
// Expression Evaluation
|
437 |
// ----------------------------
|
438 |
function evaluateExpression(expr) {
|
439 |
if (!expr) return null;
|
440 |
try {
|
441 |
let evalExpr = expr;
|
|
|
442 |
for (const [varName, varValue] of Object.entries(variables)) {
|
443 |
-
|
|
|
|
|
|
|
|
|
444 |
}
|
445 |
if (evalExpr.includes('=')) {
|
446 |
const [varName, value] = evalExpr.split('=').map(s => s.trim());
|
@@ -459,7 +460,7 @@
|
|
459 |
}
|
460 |
|
461 |
// ----------------------------
|
462 |
-
// Export Workflow to Code (DFS-based)
|
463 |
// ----------------------------
|
464 |
function getChild(node, portSelector) {
|
465 |
const port = node.querySelector(portSelector);
|
@@ -467,11 +468,9 @@
|
|
467 |
const conn = connections.find(c => c.from === port);
|
468 |
return conn ? conn.to.parentElement : null;
|
469 |
}
|
470 |
-
|
471 |
function exportWorkflowToLanguage(language) {
|
472 |
let visited = new Set();
|
473 |
let code = "";
|
474 |
-
|
475 |
function exportNode(node, indentLevel) {
|
476 |
let indent = " ".repeat(indentLevel);
|
477 |
if (visited.has(node.dataset.id)) return "";
|
@@ -598,7 +597,7 @@
|
|
598 |
default:
|
599 |
nodeCode += indent + `// Unhandled node type: ${node.dataset.type}\n`;
|
600 |
}
|
601 |
-
// For non-control nodes, append the next node if
|
602 |
if (node.dataset.type !== "If" && node.dataset.type !== "WhileLoop" && node.dataset.type !== "ForLoop") {
|
603 |
let child = getChild(node, '.port-output');
|
604 |
if (child) {
|
@@ -607,8 +606,6 @@
|
|
607 |
}
|
608 |
return nodeCode;
|
609 |
}
|
610 |
-
|
611 |
-
// Find starting nodes (with no incoming connection)
|
612 |
let startNodes = nodes.filter(n => !connections.some(c => c.to.parentElement === n));
|
613 |
startNodes.forEach(node => {
|
614 |
code += exportNode(node, 0);
|
@@ -732,7 +729,6 @@
|
|
732 |
executeNode(nextNode, loopControl, funcContext);
|
733 |
}
|
734 |
}
|
735 |
-
|
736 |
function executeNode(node, loopControl = { break: false, continue: false }, funcContext = null) {
|
737 |
if (node.dataset.executed || loopControl.break) return;
|
738 |
node.dataset.executed = true;
|
@@ -748,9 +744,9 @@
|
|
748 |
if (typeof error === 'string' && error.startsWith('Error')) markError(node, error);
|
749 |
executeNext(node, 'output', loopControl, funcContext);
|
750 |
} else if (type === 'Print') {
|
751 |
-
const
|
752 |
-
const
|
753 |
-
workflowOutput +=
|
754 |
} else if (type === 'Function') {
|
755 |
const funcName = node.querySelector('.func-name').value;
|
756 |
const args = Array.from(node.querySelectorAll('.arg-name')).map(input => input.value);
|
@@ -792,7 +788,6 @@
|
|
792 |
}
|
793 |
executeNext(node, 'output', loopControl, funcContext);
|
794 |
}
|
795 |
-
// Library Node
|
796 |
else if (type === 'Library') {
|
797 |
const libUrl = node.querySelector('.lib-url').value;
|
798 |
if (libUrl) {
|
@@ -813,11 +808,9 @@
|
|
813 |
executeNext(node, 'output', loopControl, funcContext);
|
814 |
}
|
815 |
}
|
816 |
-
// Comment Node
|
817 |
else if (type === 'Comment') {
|
818 |
executeNext(node, 'output', loopControl, funcContext);
|
819 |
}
|
820 |
-
// For Loop Node
|
821 |
else if (type === 'ForLoop') {
|
822 |
const init = node.querySelector('.init').value;
|
823 |
const condition = node.querySelector('.condition').value;
|
@@ -938,7 +931,6 @@
|
|
938 |
executeNext(node, 'output', loopControl, funcContext);
|
939 |
}
|
940 |
}
|
941 |
-
|
942 |
function runWorkflow() {
|
943 |
workflowOutput = "";
|
944 |
variables = {};
|
@@ -949,7 +941,6 @@
|
|
949 |
startNodes.forEach(node => executeNode(node));
|
950 |
alert(workflowOutput || 'No output generated! Check your connections and node settings.');
|
951 |
}
|
952 |
-
|
953 |
// ----------------------------
|
954 |
// Step-by-step execution
|
955 |
// ----------------------------
|
@@ -986,9 +977,9 @@
|
|
986 |
if (typeof error === 'string' && error.startsWith('Error')) markError(node, error);
|
987 |
nextNodes.push(getNextNode(node));
|
988 |
} else if (type === 'Print') {
|
989 |
-
const
|
990 |
-
const
|
991 |
-
console.log(
|
992 |
} else if (type === 'Add') {
|
993 |
const op1 = evaluateExpression(node.querySelector('.operand1').value);
|
994 |
const op2 = evaluateExpression(node.querySelector('.operand2').value);
|
@@ -1032,7 +1023,6 @@
|
|
1032 |
const conn = connections.find(c => c.from === port);
|
1033 |
return conn ? conn.to.parentElement : null;
|
1034 |
}
|
1035 |
-
|
1036 |
// ----------------------------
|
1037 |
// Workflow Persistence (Save/Load)
|
1038 |
// ----------------------------
|
@@ -1092,9 +1082,8 @@
|
|
1092 |
alert("Invalid JSON data.");
|
1093 |
}
|
1094 |
}
|
1095 |
-
|
1096 |
// ----------------------------
|
1097 |
-
// Export Workflow to Code
|
1098 |
// ----------------------------
|
1099 |
function exportWorkflowToLanguage(language) {
|
1100 |
let visited = new Set();
|
@@ -1225,7 +1214,7 @@
|
|
1225 |
default:
|
1226 |
nodeCode += indent + `// Unhandled node type: ${node.dataset.type}\n`;
|
1227 |
}
|
1228 |
-
// For non-control nodes,
|
1229 |
if (node.dataset.type !== "If" && node.dataset.type !== "WhileLoop" && node.dataset.type !== "ForLoop") {
|
1230 |
let child = getChild(node, '.port-output');
|
1231 |
if (child) {
|
@@ -1343,15 +1332,15 @@
|
|
1343 |
// ----------------------------
|
1344 |
// Zooming Support
|
1345 |
// ----------------------------
|
1346 |
-
canvas.addEventListener('wheel', (e) => {
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
});
|
1355 |
</script>
|
1356 |
</body>
|
1357 |
</html>
|
|
|
151 |
highestZ++;
|
152 |
node.style.zIndex = highestZ;
|
153 |
|
|
|
154 |
let html = `<div class="node-header">${type}<span class="remove-node" onclick="removeNode(this)">×</span></div>`;
|
|
|
155 |
if (type === 'Variable') {
|
156 |
html += `
|
157 |
<input type="text" class="var-name" placeholder="Variable Name">
|
|
|
166 |
`;
|
167 |
} else if (type === 'Print') {
|
168 |
html += `
|
169 |
+
<input type="text" class="print-value" placeholder='Expression to print (e.g., "Hello " + x)'>
|
170 |
<div class="port port-input" data-type="input"></div>
|
171 |
`;
|
172 |
} else if (type === 'Function') {
|
|
|
226 |
`;
|
227 |
} else if (type === 'Break' || type === 'Continue') {
|
228 |
html += `<div class="port port-input" data-type="input"></div>`;
|
229 |
+
} else if (type === 'Add' || type === 'Subtract' ||
|
230 |
+
type === 'Multiply' || type === 'Divide') {
|
231 |
html += `
|
232 |
<input type="text" class="operand1" placeholder="Operand 1">
|
233 |
<input type="text" class="operand2" placeholder="Operand 2">
|
|
|
302 |
// ----------------------------
|
303 |
function removeNode(removeButton) {
|
304 |
const node = removeButton.parentElement.parentElement;
|
|
|
305 |
connections = connections.filter(conn => conn.from.parentElement !== node && conn.to.parentElement !== node);
|
306 |
node.remove();
|
307 |
nodes = nodes.filter(n => n !== node);
|
|
|
392 |
}
|
393 |
}
|
394 |
});
|
|
|
395 |
document.addEventListener('mouseup', (e) => {
|
396 |
if (draggingNode) draggingNode = null;
|
397 |
if (draggingPort) {
|
|
|
410 |
}
|
411 |
}
|
412 |
});
|
|
|
413 |
function updateConnections() {
|
414 |
connectionsSvg.innerHTML = '';
|
415 |
const canvasRect = canvas.getBoundingClientRect();
|
|
|
429 |
}
|
430 |
|
431 |
// ----------------------------
|
432 |
+
// Expression Evaluation (with string support)
|
433 |
// ----------------------------
|
434 |
function evaluateExpression(expr) {
|
435 |
if (!expr) return null;
|
436 |
try {
|
437 |
let evalExpr = expr;
|
438 |
+
// Replace variable names with their values. If a variable is a non-numeric string, wrap in quotes.
|
439 |
for (const [varName, varValue] of Object.entries(variables)) {
|
440 |
+
let replacement = varValue;
|
441 |
+
if (typeof varValue === "string" || isNaN(varValue)) {
|
442 |
+
replacement = `"${varValue}"`;
|
443 |
+
}
|
444 |
+
evalExpr = evalExpr.replace(new RegExp(`\\b${varName}\\b`, 'g'), replacement);
|
445 |
}
|
446 |
if (evalExpr.includes('=')) {
|
447 |
const [varName, value] = evalExpr.split('=').map(s => s.trim());
|
|
|
460 |
}
|
461 |
|
462 |
// ----------------------------
|
463 |
+
// Export Workflow to Code (DFS-based, with proper indentation)
|
464 |
// ----------------------------
|
465 |
function getChild(node, portSelector) {
|
466 |
const port = node.querySelector(portSelector);
|
|
|
468 |
const conn = connections.find(c => c.from === port);
|
469 |
return conn ? conn.to.parentElement : null;
|
470 |
}
|
|
|
471 |
function exportWorkflowToLanguage(language) {
|
472 |
let visited = new Set();
|
473 |
let code = "";
|
|
|
474 |
function exportNode(node, indentLevel) {
|
475 |
let indent = " ".repeat(indentLevel);
|
476 |
if (visited.has(node.dataset.id)) return "";
|
|
|
597 |
default:
|
598 |
nodeCode += indent + `// Unhandled node type: ${node.dataset.type}\n`;
|
599 |
}
|
600 |
+
// For non-control nodes, append the next connected node (if any)
|
601 |
if (node.dataset.type !== "If" && node.dataset.type !== "WhileLoop" && node.dataset.type !== "ForLoop") {
|
602 |
let child = getChild(node, '.port-output');
|
603 |
if (child) {
|
|
|
606 |
}
|
607 |
return nodeCode;
|
608 |
}
|
|
|
|
|
609 |
let startNodes = nodes.filter(n => !connections.some(c => c.to.parentElement === n));
|
610 |
startNodes.forEach(node => {
|
611 |
code += exportNode(node, 0);
|
|
|
729 |
executeNode(nextNode, loopControl, funcContext);
|
730 |
}
|
731 |
}
|
|
|
732 |
function executeNode(node, loopControl = { break: false, continue: false }, funcContext = null) {
|
733 |
if (node.dataset.executed || loopControl.break) return;
|
734 |
node.dataset.executed = true;
|
|
|
744 |
if (typeof error === 'string' && error.startsWith('Error')) markError(node, error);
|
745 |
executeNext(node, 'output', loopControl, funcContext);
|
746 |
} else if (type === 'Print') {
|
747 |
+
const expr = node.querySelector('.print-value').value;
|
748 |
+
const result = evaluateExpression(expr);
|
749 |
+
workflowOutput += (result !== null ? result : "") + "\n";
|
750 |
} else if (type === 'Function') {
|
751 |
const funcName = node.querySelector('.func-name').value;
|
752 |
const args = Array.from(node.querySelectorAll('.arg-name')).map(input => input.value);
|
|
|
788 |
}
|
789 |
executeNext(node, 'output', loopControl, funcContext);
|
790 |
}
|
|
|
791 |
else if (type === 'Library') {
|
792 |
const libUrl = node.querySelector('.lib-url').value;
|
793 |
if (libUrl) {
|
|
|
808 |
executeNext(node, 'output', loopControl, funcContext);
|
809 |
}
|
810 |
}
|
|
|
811 |
else if (type === 'Comment') {
|
812 |
executeNext(node, 'output', loopControl, funcContext);
|
813 |
}
|
|
|
814 |
else if (type === 'ForLoop') {
|
815 |
const init = node.querySelector('.init').value;
|
816 |
const condition = node.querySelector('.condition').value;
|
|
|
931 |
executeNext(node, 'output', loopControl, funcContext);
|
932 |
}
|
933 |
}
|
|
|
934 |
function runWorkflow() {
|
935 |
workflowOutput = "";
|
936 |
variables = {};
|
|
|
941 |
startNodes.forEach(node => executeNode(node));
|
942 |
alert(workflowOutput || 'No output generated! Check your connections and node settings.');
|
943 |
}
|
|
|
944 |
// ----------------------------
|
945 |
// Step-by-step execution
|
946 |
// ----------------------------
|
|
|
977 |
if (typeof error === 'string' && error.startsWith('Error')) markError(node, error);
|
978 |
nextNodes.push(getNextNode(node));
|
979 |
} else if (type === 'Print') {
|
980 |
+
const expr = node.querySelector('.print-value').value;
|
981 |
+
const result = evaluateExpression(expr);
|
982 |
+
console.log(result);
|
983 |
} else if (type === 'Add') {
|
984 |
const op1 = evaluateExpression(node.querySelector('.operand1').value);
|
985 |
const op2 = evaluateExpression(node.querySelector('.operand2').value);
|
|
|
1023 |
const conn = connections.find(c => c.from === port);
|
1024 |
return conn ? conn.to.parentElement : null;
|
1025 |
}
|
|
|
1026 |
// ----------------------------
|
1027 |
// Workflow Persistence (Save/Load)
|
1028 |
// ----------------------------
|
|
|
1082 |
alert("Invalid JSON data.");
|
1083 |
}
|
1084 |
}
|
|
|
1085 |
// ----------------------------
|
1086 |
+
// Export Workflow to Code
|
1087 |
// ----------------------------
|
1088 |
function exportWorkflowToLanguage(language) {
|
1089 |
let visited = new Set();
|
|
|
1214 |
default:
|
1215 |
nodeCode += indent + `// Unhandled node type: ${node.dataset.type}\n`;
|
1216 |
}
|
1217 |
+
// For non-control nodes, add the next connected node
|
1218 |
if (node.dataset.type !== "If" && node.dataset.type !== "WhileLoop" && node.dataset.type !== "ForLoop") {
|
1219 |
let child = getChild(node, '.port-output');
|
1220 |
if (child) {
|
|
|
1332 |
// ----------------------------
|
1333 |
// Zooming Support
|
1334 |
// ----------------------------
|
1335 |
+
// canvas.addEventListener('wheel', (e) => {
|
1336 |
+
// e.preventDefault();
|
1337 |
+
// if (e.deltaY < 0) {
|
1338 |
+
// zoomFactor *= 1.1;
|
1339 |
+
// } else {
|
1340 |
+
// zoomFactor /= 1.1;
|
1341 |
+
// }
|
1342 |
+
// canvas.style.transform = `scale(${zoomFactor})`;
|
1343 |
+
// });
|
1344 |
</script>
|
1345 |
</body>
|
1346 |
</html>
|