2026-02-20 07:57:54 +00:00
|
|
|
import * as Blockly from 'blockly';
|
|
|
|
|
|
|
|
|
|
const BROWSER_STORAGE_KEY = 'esp32block_projects';
|
|
|
|
|
|
|
|
|
|
let workspace = null;
|
|
|
|
|
let captureOutput = null;
|
|
|
|
|
let writeFile = null;
|
|
|
|
|
let checkConnected = null;
|
|
|
|
|
|
2026-04-17 10:34:46 +00:00
|
|
|
let browserList;
|
|
|
|
|
let browserNameInput;
|
|
|
|
|
let browserSaveBtn, browserLoadBtn, browserDownloadBtn, browserDeleteBtn;
|
2026-02-20 07:57:54 +00:00
|
|
|
|
|
|
|
|
let browserSelected = null;
|
|
|
|
|
|
|
|
|
|
export function initProjectsDialog(deps) {
|
|
|
|
|
workspace = deps.workspace;
|
|
|
|
|
captureOutput = deps.captureDeviceOutput;
|
|
|
|
|
writeFile = deps.writeFileToDevice;
|
|
|
|
|
checkConnected = deps.isConnected;
|
|
|
|
|
|
|
|
|
|
browserList = document.getElementById('browser-list');
|
|
|
|
|
browserNameInput = document.getElementById('browser-save-name');
|
|
|
|
|
browserSaveBtn = document.getElementById('browser-save-btn');
|
|
|
|
|
browserLoadBtn = document.getElementById('browser-load-btn');
|
2026-04-17 10:34:46 +00:00
|
|
|
browserDownloadBtn = document.getElementById('browser-download-btn');
|
2026-02-20 07:57:54 +00:00
|
|
|
browserDeleteBtn = document.getElementById('browser-delete-btn');
|
|
|
|
|
|
|
|
|
|
browserSaveBtn.addEventListener('click', saveBrowser);
|
|
|
|
|
browserLoadBtn.addEventListener('click', loadBrowser);
|
2026-04-17 10:34:46 +00:00
|
|
|
browserDownloadBtn.addEventListener('click', downloadBrowser);
|
2026-02-20 07:57:54 +00:00
|
|
|
browserDeleteBtn.addEventListener('click', deleteBrowser);
|
|
|
|
|
|
|
|
|
|
refreshBrowserList();
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 08:13:27 +00:00
|
|
|
export function refreshAll() {
|
|
|
|
|
refreshBrowserList();
|
2026-04-17 10:34:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function saveCurrentWorkspaceToDevice(preferredName = 'main') {
|
|
|
|
|
if (!workspace || !writeFile || !checkConnected || !checkConnected()) return null;
|
|
|
|
|
const filename = preferredName.endsWith('.blk') ? preferredName : preferredName + '.blk';
|
|
|
|
|
const state = Blockly.serialization.workspaces.save(workspace);
|
|
|
|
|
const json = JSON.stringify(state);
|
|
|
|
|
await writeFile(json, filename);
|
|
|
|
|
return filename;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function loadWorkspaceFromDevice(preferredName = 'main') {
|
|
|
|
|
if (!workspace || !captureOutput || !checkConnected || !checkConnected()) return null;
|
|
|
|
|
const filename = preferredName.endsWith('.blk') ? preferredName : preferredName + '.blk';
|
|
|
|
|
const raw = await captureOutput(
|
|
|
|
|
`f=open('${filename}','r')\nprint(f.read(),end='')\nf.close()`
|
|
|
|
|
);
|
|
|
|
|
const state = JSON.parse(raw.trim());
|
|
|
|
|
Blockly.serialization.workspaces.load(state, workspace);
|
|
|
|
|
return filename;
|
2026-02-20 07:57:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── Browser column ──────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
function getBrowserProjects() {
|
|
|
|
|
try {
|
|
|
|
|
return JSON.parse(localStorage.getItem(BROWSER_STORAGE_KEY) || '{}');
|
|
|
|
|
} catch { return {}; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setBrowserProjects(projects) {
|
|
|
|
|
localStorage.setItem(BROWSER_STORAGE_KEY, JSON.stringify(projects));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function refreshBrowserList() {
|
|
|
|
|
const projects = getBrowserProjects();
|
|
|
|
|
const names = Object.keys(projects).sort();
|
|
|
|
|
browserList.innerHTML = '';
|
|
|
|
|
browserSelected = null;
|
|
|
|
|
updateBrowserButtons();
|
|
|
|
|
|
|
|
|
|
if (names.length === 0) {
|
|
|
|
|
browserList.innerHTML = '<li class="empty-msg">No saved projects</li>';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const name of names) {
|
|
|
|
|
const li = document.createElement('li');
|
|
|
|
|
li.textContent = name;
|
|
|
|
|
li.addEventListener('click', () => selectBrowserItem(name, li));
|
|
|
|
|
li.addEventListener('dblclick', () => { selectBrowserItem(name, li); loadBrowser(); });
|
|
|
|
|
browserList.appendChild(li);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function selectBrowserItem(name, li) {
|
|
|
|
|
browserList.querySelectorAll('li').forEach(el => el.classList.remove('selected'));
|
|
|
|
|
li.classList.add('selected');
|
|
|
|
|
browserSelected = name;
|
|
|
|
|
browserNameInput.value = name;
|
|
|
|
|
updateBrowserButtons();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateBrowserButtons() {
|
|
|
|
|
browserLoadBtn.disabled = !browserSelected;
|
2026-04-17 10:34:46 +00:00
|
|
|
browserDownloadBtn.disabled = !browserSelected;
|
2026-02-20 07:57:54 +00:00
|
|
|
browserDeleteBtn.disabled = !browserSelected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function saveBrowser() {
|
|
|
|
|
const name = browserNameInput.value.trim();
|
|
|
|
|
if (!name) return;
|
|
|
|
|
const projects = getBrowserProjects();
|
|
|
|
|
projects[name] = Blockly.serialization.workspaces.save(workspace);
|
|
|
|
|
setBrowserProjects(projects);
|
|
|
|
|
browserNameInput.value = '';
|
|
|
|
|
refreshBrowserList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function loadBrowser() {
|
|
|
|
|
if (!browserSelected) return;
|
|
|
|
|
const projects = getBrowserProjects();
|
|
|
|
|
const state = projects[browserSelected];
|
|
|
|
|
if (!state) return;
|
|
|
|
|
Blockly.serialization.workspaces.load(state, workspace);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function deleteBrowser() {
|
|
|
|
|
if (!browserSelected) return;
|
|
|
|
|
const projects = getBrowserProjects();
|
|
|
|
|
delete projects[browserSelected];
|
|
|
|
|
setBrowserProjects(projects);
|
|
|
|
|
refreshBrowserList();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 10:34:46 +00:00
|
|
|
function downloadBrowser() {
|
|
|
|
|
if (!browserSelected) return;
|
|
|
|
|
const projects = getBrowserProjects();
|
|
|
|
|
const state = projects[browserSelected];
|
|
|
|
|
if (!state) return;
|
|
|
|
|
const json = JSON.stringify(state, null, 2);
|
|
|
|
|
const blob = new Blob([json], { type: 'application/json' });
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
a.href = url;
|
|
|
|
|
a.download = `${browserSelected}.blk`;
|
|
|
|
|
document.body.appendChild(a);
|
|
|
|
|
a.click();
|
|
|
|
|
document.body.removeChild(a);
|
|
|
|
|
URL.revokeObjectURL(url);
|
2026-02-20 07:57:54 +00:00
|
|
|
}
|