Files
A screen that receives a file, shows its contents, and saves a file.
Receiving a file
(node at: '.asText' on: #change sendFileText: #tookText:text:)
(node at: '.asBytes' on: #change sendFileBytes: #tookBytes:bytes:)
Other events read their value and send a message immediately. Reading a file takes time, so the message is sent when reading finishes. The handler receives the file name and contents. Closing the dialog without choosing a file does nothing.
File selection, paste (on: #paste), and drag-and-drop (on: #drop) can use the same handler.
Text and bytes
sendFileText: is for files read as text, such as CSV. sendFileBytes: delivers the file contents as a byte array. Reading a report or a spreadsheet as text replaces undecodable bytes with the replacement character and the original cannot be recovered, which is why the two are separate.
Saving a file
Screen >> saveCsv = ( App save: 'out.csv' type: 'text/csv' text: text. self ).
Screen >> saveSame = ( App save: name type: 'application/octet-stream' bytes: held. self ).
The browser's own method (create a link element, click it, discard it, revoke the object URL) is four steps, and forgetting the last one leaks memory. This is one message.
Character encodings
Bytes has size, asText, asTextIn:, and asCodes, and is constructed with Bytes empty, Bytes ofText:, or Bytes ofCodes:.
asText decodes as UTF-8. A Japanese email subject arrives as =?ISO-2022-JP?B?GyRCJDMkcyRLJEEkTxsoQg==?=: bytes in the encoding named in the header, wrapped in base64. To read it, decode the base64 and then decode the bytes with the named encoding.
b := (Base64 decode: 'GyRCJDMkcyRLJEEkTxsoQg==') orElse: [Bytes empty].
b asText printNl. "$B$3$s$K$A$O(B — decoded as UTF-8"
(b asTextIn: 'ISO-2022-JP') printNl. "Some('こんにちは')"
Base64 decode: and asTextIn: return a Maybe so that malformed external input does not raise. Bytes that cannot be decoded do not raise either; they become the replacement character.
Decoders for other encodings, such as the Q form (=E9=BB=92, hexadecimal), can be written in LPScript with Bytes ofCodes: and asCodes, which convert between an integer array and a byte array. Values outside 0–255 are an error.
There is no encoding to anything other than UTF-8, because the browser's TextEncoder produces only UTF-8.
Bytes can be passed to a Worker.
Testing
A file dialog and a save location exist only in a browser. This screen is tested in a real browser: a file is placed in the input element, and the saved file is read back from disk and compared byte for byte.