tricu

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

output-app.js (2816B)


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