tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

output-app.js (2870B)


      1 // One output surface. The saved payload carries its own provenance/format;
      2 // changing controls cannot relabel an earlier result or change its download.
      3 export function createOutput() {
      4     const text = document.getElementById('result');
      5     const provenance = document.getElementById('output-provenance');
      6     const copy = document.getElementById('copy-output');
      7     const download = document.getElementById('download-output');
      8     let saved, busy = false;
      9     const controls = (working) => { busy = working; copy.disabled = download.disabled = busy || !saved; };
     10     function clear() { saved = undefined; text.textContent = ''; text.className = ''; provenance.textContent = 'Evaluate an expression, or show a stored definition. Nothing runs automatically.'; controls(busy); }
     11     function show(value, filename, description) {
     12         saved = { text: value, filename };
     13         text.textContent = value.slice(0, 16_384);
     14         text.className = '';
     15         provenance.textContent = description + (value.length > 16_384 ? ' · Preview: first 16,384 characters. Copy and Download include the complete output.' : ' · Complete output.');
     16         controls(busy);
     17     }
     18     function file(value, name, description) {
     19         show(value.text, `${name.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 64)}.${value.extension}`, `${description} · ${value.bytes.toLocaleString()} UTF-8 bytes`);
     20     }
     21     function result(value, description) {
     22         if ('file' in value) {
     23             file(value.file, 'result', `${description} · ${value.type}`);
     24             return;
     25         }
     26         if (value.type === 'tree' || value.type === 'list')
     27             throw new Error('Select tricu source or DAG to inspect tree results');
     28         const content = typeof value.value === 'string' ? value.value : JSON.stringify(value.value, null, 2);
     29         show(content, value.type === 'record' || value.type === 'bytes' ? 'result.json' : 'result.txt', `${description} · ${value.type}`);
     30     }
     31     copy.onclick = async () => {
     32         const value = saved;
     33         if (!value)
     34             return;
     35         try {
     36             await navigator.clipboard.writeText(value.text);
     37             if (saved === value)
     38                 provenance.textContent += ' · Copied.';
     39         }
     40         catch {
     41             if (saved === value)
     42                 provenance.textContent += ' · Clipboard unavailable; use Download.';
     43         }
     44     };
     45     download.onclick = () => {
     46         if (!saved)
     47             return;
     48         const url = URL.createObjectURL(new Blob([saved.text], { type: 'text/plain;charset=utf-8' }));
     49         const a = document.createElement('a');
     50         a.href = url;
     51         a.download = saved.filename;
     52         document.body.append(a);
     53         a.click();
     54         a.remove();
     55         setTimeout(() => URL.revokeObjectURL(url), 1000);
     56     };
     57     clear();
     58     return { clear, controls, file, result };
     59 }