// The Circuit widget: a program's circuit as the engine drew it (engine::svg, the // Studio's picture). Clicking a gate selects its operation (the model's // `selected`, its index in the program; clicking it again clears it). When the // drawing marks whose hand each gate is in, "Who wrote it" shows or hides the // marks. Nothing here redraws the circuit: the SVG is the engine's, its labels // escaped by the engine. function el(tag, attrs = {}, ...kids) { const e = document.createElement(tag); for (const [k, v] of Object.entries(attrs)) { if (k === 'text') e.textContent = v; else if (v != null) e.setAttribute(k, String(v)); } for (const k of kids) if (k != null) e.append(k); return e; } function render({ model, el: host }) { const root = el('div', { class: 'wq wq-circuit-widget' }); host.append(root); let marked = true; function draw() { const d = model.get('data') || {}; const selected = model.get('selected'); const box = el('div', { class: 'wq-scroll' }); box.innerHTML = d.svg || ''; const svg = box.querySelector('svg'); const bar = el('div', { class: 'wq-bar' }); if (svg && Array.isArray(d.key) && d.key.length) { const id = `wq-hands-${Math.random().toString(36).slice(2)}`; const check = el('input', { type: 'checkbox', id }); check.checked = marked; check.addEventListener('change', () => { marked = check.checked; svg.classList.toggle('wq-unmarked', !marked); }); bar.append(el('label', { for: id, class: 'wq-check' }, check, el('span', { text: 'Who wrote it' }))); svg.classList.toggle('wq-unmarked', !marked); } const status = el('span', { class: 'wq-muted' }); if (svg) { for (const g of svg.querySelectorAll('.qc-item[data-op]')) { const op = Number(g.dataset.op); g.classList.add('wq-pick'); g.classList.toggle('wq-selected', selected === op); if (selected === op) status.textContent = `operation ${op}: ${g.querySelector('title')?.textContent || ''}`; g.addEventListener('click', () => { model.set('selected', model.get('selected') === op ? null : op); model.save_changes(); }); } } if (!status.textContent) status.textContent = 'Click a gate to select its operation.'; bar.append(status); root.replaceChildren(box, bar); } draw(); model.on('change:data', draw); model.on('change:selected', draw); return () => { model.off('change:data', draw); model.off('change:selected', draw); }; } export default { render };