Spaces:
Running
Running
blocks to js
Browse files
client/src/components/BlockEditor/BlockEditor.tsx
CHANGED
|
@@ -627,6 +627,27 @@ function generateCodeFromWorkspace(ws: any): string {
|
|
| 627 |
return code.filter(Boolean).join('\n');
|
| 628 |
}
|
| 629 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 630 |
export default function BlockEditor() {
|
| 631 |
const blocklyDiv = useRef<HTMLDivElement>(null);
|
| 632 |
const workspaceRef = useRef<Blockly.WorkspaceSvg | null>(null);
|
|
@@ -635,8 +656,6 @@ export default function BlockEditor() {
|
|
| 635 |
const activeFileId = useEditorStore((s) => s.activeFileId);
|
| 636 |
const getBlocksXml = useEditorStore((s) => s.getBlocksXml);
|
| 637 |
const setBlocksXml = useEditorStore((s) => s.setBlocksXml);
|
| 638 |
-
const setBlockCode = useEditorStore((s) => s.setBlockCode);
|
| 639 |
-
const saveGeneratedCodeToFile = useEditorStore((s) => s.saveGeneratedCodeToFile);
|
| 640 |
const projectIdRef = useRef(currentProject?.id);
|
| 641 |
projectIdRef.current = currentProject?.id;
|
| 642 |
const lastPointerEmitRef = useRef(0);
|
|
@@ -979,6 +998,10 @@ export default function BlockEditor() {
|
|
| 979 |
Blockly.Xml.domToWorkspace(dom, ws2);
|
| 980 |
try { (ws2 as any).clearSelection(); } catch {}
|
| 981 |
try { ws2.zoomToFit(); } catch {}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 982 |
} catch (e) {
|
| 983 |
console.error('[WS Reload] FAILED to apply deferred XML:', e);
|
| 984 |
}
|
|
@@ -1063,19 +1086,7 @@ export default function BlockEditor() {
|
|
| 1063 |
console.log('[saveBlocks] SAVING blocks for file:', currentFileId, 'xml length:', xml.length, 'topBlocks:', ws.getTopBlocks(false).length, '(old:', savedXml?.length, ')');
|
| 1064 |
setBlocksXml(currentFileId, xml);
|
| 1065 |
emitBlockStateSync(currentFileId, xml);
|
| 1066 |
-
|
| 1067 |
-
try {
|
| 1068 |
-
// Try manual code generation first (uses our compile functions directly)
|
| 1069 |
-
finalCode = generateCodeFromWorkspace(ws);
|
| 1070 |
-
// Fall back to Blockly's generator if manual output is empty but blocks exist
|
| 1071 |
-
if (!finalCode && ws.getTopBlocks(false).length > 0) {
|
| 1072 |
-
finalCode = javascriptGenerator.workspaceToCode(ws) || '';
|
| 1073 |
-
}
|
| 1074 |
-
} catch (e) {
|
| 1075 |
-
// code generation failed - file content stays empty so compileWeb defaults
|
| 1076 |
-
}
|
| 1077 |
-
setBlockCode(currentFileId, finalCode);
|
| 1078 |
-
saveGeneratedCodeToFile(currentFileId, finalCode);
|
| 1079 |
};
|
| 1080 |
ws.addChangeListener(saveBlocks);
|
| 1081 |
|
|
@@ -1154,6 +1165,9 @@ export default function BlockEditor() {
|
|
| 1154 |
Blockly.Xml.domToWorkspace(dom, ws);
|
| 1155 |
try { (ws as any).clearSelection(); } catch {}
|
| 1156 |
try { ws.zoomToFit(); } catch {}
|
|
|
|
|
|
|
|
|
|
| 1157 |
} catch (e) {
|
| 1158 |
console.error('[WS Reload] FAILED to load blocks from XML:', e);
|
| 1159 |
}
|
|
@@ -1234,6 +1248,9 @@ export default function BlockEditor() {
|
|
| 1234 |
useCollaborationStore.setState({ pendingBlockConnects: unprocessed });
|
| 1235 |
}
|
| 1236 |
ws.render();
|
|
|
|
|
|
|
|
|
|
| 1237 |
}
|
| 1238 |
remoteUpdateRef.current = false;
|
| 1239 |
}, [pendingBlockConnects, blocksXmlForFile]);
|
|
@@ -1255,6 +1272,9 @@ export default function BlockEditor() {
|
|
| 1255 |
}
|
| 1256 |
}
|
| 1257 |
remoteUpdateRef.current = false;
|
|
|
|
|
|
|
|
|
|
| 1258 |
}, [pendingBlockChanges]);
|
| 1259 |
|
| 1260 |
// Create blocks on receiver when remote user drags a new block from the toolbox
|
|
@@ -1294,6 +1314,9 @@ export default function BlockEditor() {
|
|
| 1294 |
const xml = Blockly.Xml.domToText(dom);
|
| 1295 |
console.log('[PendingCreate] updating blocksXml after creating blocks');
|
| 1296 |
useEditorStore.getState().setBlocksXml(activeFileId, xml);
|
|
|
|
|
|
|
|
|
|
| 1297 |
requestAnimationFrame(() => {
|
| 1298 |
try { syncCustomFunctionBlocks(ws); } catch {}
|
| 1299 |
try { rebuildToolbox(ws); } catch {}
|
|
|
|
| 627 |
return code.filter(Boolean).join('\n');
|
| 628 |
}
|
| 629 |
|
| 630 |
+
// Regenerate the compiled code for a workspace and persist it to the store and
|
| 631 |
+
// file tree. Called on local saves and after remote XML reloads, which skip
|
| 632 |
+
// saveBlocks because its change listener early-returns while remoteUpdateRef
|
| 633 |
+
// is set. Without this, the code panel would not reflect collaborator changes.
|
| 634 |
+
function refreshCodeForWorkspace(ws: any, fileId: string): void {
|
| 635 |
+
let finalCode = '';
|
| 636 |
+
try {
|
| 637 |
+
// Try manual code generation first (uses our compile functions directly)
|
| 638 |
+
finalCode = generateCodeFromWorkspace(ws);
|
| 639 |
+
// Fall back to Blockly's generator if manual output is empty but blocks exist
|
| 640 |
+
if (!finalCode && ws.getTopBlocks(false).length > 0) {
|
| 641 |
+
finalCode = javascriptGenerator.workspaceToCode(ws) || '';
|
| 642 |
+
}
|
| 643 |
+
} catch (e) {
|
| 644 |
+
finalCode = '';
|
| 645 |
+
}
|
| 646 |
+
const store = useEditorStore.getState();
|
| 647 |
+
store.setBlockCode(fileId, finalCode);
|
| 648 |
+
store.saveGeneratedCodeToFile(fileId, finalCode);
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
export default function BlockEditor() {
|
| 652 |
const blocklyDiv = useRef<HTMLDivElement>(null);
|
| 653 |
const workspaceRef = useRef<Blockly.WorkspaceSvg | null>(null);
|
|
|
|
| 656 |
const activeFileId = useEditorStore((s) => s.activeFileId);
|
| 657 |
const getBlocksXml = useEditorStore((s) => s.getBlocksXml);
|
| 658 |
const setBlocksXml = useEditorStore((s) => s.setBlocksXml);
|
|
|
|
|
|
|
| 659 |
const projectIdRef = useRef(currentProject?.id);
|
| 660 |
projectIdRef.current = currentProject?.id;
|
| 661 |
const lastPointerEmitRef = useRef(0);
|
|
|
|
| 998 |
Blockly.Xml.domToWorkspace(dom, ws2);
|
| 999 |
try { (ws2 as any).clearSelection(); } catch {}
|
| 1000 |
try { ws2.zoomToFit(); } catch {}
|
| 1001 |
+
// Regenerate the compiled code now that the workspace reflects
|
| 1002 |
+
// the collaborator's XML (saveBlocks skips during remote loads).
|
| 1003 |
+
const currentFileId = useEditorStore.getState().activeFileId;
|
| 1004 |
+
if (currentFileId) refreshCodeForWorkspace(ws2, currentFileId);
|
| 1005 |
} catch (e) {
|
| 1006 |
console.error('[WS Reload] FAILED to apply deferred XML:', e);
|
| 1007 |
}
|
|
|
|
| 1086 |
console.log('[saveBlocks] SAVING blocks for file:', currentFileId, 'xml length:', xml.length, 'topBlocks:', ws.getTopBlocks(false).length, '(old:', savedXml?.length, ')');
|
| 1087 |
setBlocksXml(currentFileId, xml);
|
| 1088 |
emitBlockStateSync(currentFileId, xml);
|
| 1089 |
+
refreshCodeForWorkspace(ws, currentFileId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1090 |
};
|
| 1091 |
ws.addChangeListener(saveBlocks);
|
| 1092 |
|
|
|
|
| 1165 |
Blockly.Xml.domToWorkspace(dom, ws);
|
| 1166 |
try { (ws as any).clearSelection(); } catch {}
|
| 1167 |
try { ws.zoomToFit(); } catch {}
|
| 1168 |
+
// Regenerate the compiled code now that the workspace reflects the synced
|
| 1169 |
+
// XML (saveBlocks skips while remoteUpdateRef is set).
|
| 1170 |
+
if (activeFileId) refreshCodeForWorkspace(ws, activeFileId);
|
| 1171 |
} catch (e) {
|
| 1172 |
console.error('[WS Reload] FAILED to load blocks from XML:', e);
|
| 1173 |
}
|
|
|
|
| 1248 |
useCollaborationStore.setState({ pendingBlockConnects: unprocessed });
|
| 1249 |
}
|
| 1250 |
ws.render();
|
| 1251 |
+
// saveBlocks skips while remoteUpdateRef is set, so refresh the compiled
|
| 1252 |
+
// code explicitly after applying remote connections.
|
| 1253 |
+
if (activeFileId) refreshCodeForWorkspace(ws, activeFileId);
|
| 1254 |
}
|
| 1255 |
remoteUpdateRef.current = false;
|
| 1256 |
}, [pendingBlockConnects, blocksXmlForFile]);
|
|
|
|
| 1272 |
}
|
| 1273 |
}
|
| 1274 |
remoteUpdateRef.current = false;
|
| 1275 |
+
// saveBlocks skips while remoteUpdateRef is set, so refresh the compiled
|
| 1276 |
+
// code explicitly after applying remote field value changes.
|
| 1277 |
+
if (ws && activeFileId) refreshCodeForWorkspace(ws, activeFileId);
|
| 1278 |
}, [pendingBlockChanges]);
|
| 1279 |
|
| 1280 |
// Create blocks on receiver when remote user drags a new block from the toolbox
|
|
|
|
| 1314 |
const xml = Blockly.Xml.domToText(dom);
|
| 1315 |
console.log('[PendingCreate] updating blocksXml after creating blocks');
|
| 1316 |
useEditorStore.getState().setBlocksXml(activeFileId, xml);
|
| 1317 |
+
// saveBlocks skips while remoteUpdateRef is set, so refresh the
|
| 1318 |
+
// compiled code explicitly after creating collaborator blocks.
|
| 1319 |
+
refreshCodeForWorkspace(ws, activeFileId);
|
| 1320 |
requestAnimationFrame(() => {
|
| 1321 |
try { syncCustomFunctionBlocks(ws); } catch {}
|
| 1322 |
try { rebuildToolbox(ws); } catch {}
|