blockly/client/src/index.ts

126 lines
3.2 KiB
TypeScript

/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import * as Blockly from 'blockly';
import * as newBlocks from './blocks';
import { javascriptGenerator } from 'blockly/javascript';
import { save, load } from './serialization';
import { toolbox } from './toolbox';
import { registerContinuousToolbox } from '@blockly/continuous-toolbox';
import Cookies from 'js-cookie';
import * as nano from 'nano';
import './index.css';
function randomValueHex(length: number) {
let hex = '';
for (let i = 0; i < length; i++)
hex += Math.floor(Math.random() * 256).toString(16);
return hex;
}
let browserId = Cookies.get('id');
if (!browserId) {
browserId = randomValueHex(24);
if (!Cookies.get('id'))
Cookies.set('id', browserId);
}
const blocks = Object.values(newBlocks).reduce((acc, val) => {
acc = { ...acc, ...val.block };
return acc;
}, {});
const generators = Object.values(newBlocks).reduce((acc, val) => {
acc = { ...acc, [Object.keys(val.block)[0]]: val.toJS };
return acc;
}, {});
// Register the blocks and generator with Blockly
Blockly.common.defineBlocks(blocks);
Object.assign(javascriptGenerator.forBlock, generators);
registerContinuousToolbox();
// Set up UI elements and inject Blockly
const codeDiv = document.getElementById('outputDiv')?.firstChild;
const outputDiv = document.getElementById('output');
const blocklyDiv = document.getElementById('blocklyDiv');
if (!blocklyDiv) {
throw new Error(`div with id 'blocklyDiv' not found`);
}
const ws = Blockly.inject(
blocklyDiv,
{
toolbox,
plugins: {
flyoutsVerticalToolbox: 'ContinuousFlyout',
metricsManager: 'ContinuousMetrics',
toolbox: 'ContinuousToolbox',
},
},
);
// This function resets the code and output divs, shows the
// generated code from the workspace, and evals the code.
// In a real application, you probably shouldn't use `eval`.
const runCode = () => {
const code = javascriptGenerator.workspaceToCode(ws as Blockly.Workspace);
// console.dir(code);
try {
fetch(
'http://10.0.64.121:8081/set/' + browserId,
{
method: 'POST',
body: code,
}
);
}
catch (err) {
window.alert('Error');
}
if (codeDiv) codeDiv.textContent = code;
// if (outputDiv) outputDiv.innerHTML = '';
// eval(code);
};
if (ws) {
(window as any)['ws'] = ws;
(window as any)['save_ws'] = () => save(ws);
// Load the initial state from storage and run the code.
load(ws);
runCode();
// Every time the workspace changes state, save the changes to storage.
ws.addChangeListener((e: Blockly.Events.Abstract) => {
// UI events are things like scrolling, zooming, etc.
// No need to save after one of these.
if (e.isUiEvent) return;
save(ws);
});
// Whenever the workspace changes meaningfully, run the code again.
ws.addChangeListener((e: Blockly.Events.Abstract) => {
// Don't run the code when the workspace finishes loading; we're
// already running it once when the application starts.
// Don't run the code during drags; we might have invalid state.
if (
e.isUiEvent ||
e.type == Blockly.Events.FINISHED_LOADING ||
ws.isDragging()
) {
return;
}
runCode();
});
}