const BlockType = require('../../extension-support/block-type'); const ArgumentType = require('../../extension-support/argument-type'); const { validateArray } = require('../../util/json-block-utilities'); const AHHHHHHHHHHHHHH = require('../../util/array buffer'); const BufferStuff = new AHHHHHHHHHHHHHH(); /** * Class for File blocks * @constructor */ class JgFilesBlocks { constructor (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; } /** * @returns {object} metadata for this extension and its blocks. */ getInfo () { return { id: 'jgFiles', name: 'Files (legacy)', color1: '#ffbb00', color2: '#ffaa00', // docsURI: 'https://docs.turbowarp.org/blocks', blocks: [ { opcode: 'isFileReaderSupported', text: 'can files be used?', disableMonitor: false, blockType: BlockType.BOOLEAN }, { opcode: 'askUserForFileOfType', text: 'ask user for a file of type [FILE_TYPE]', disableMonitor: true, blockType: BlockType.REPORTER, arguments: { FILE_TYPE: { type: ArgumentType.STRING, defaultValue: 'txt savefile' } } }, { opcode: 'askUserForFileOfTypeAsArrayBuffer', text: 'ask user for an array buffer file of type [FILE_TYPE]', disableMonitor: true, blockType: BlockType.REPORTER, arguments: { FILE_TYPE: { type: ArgumentType.STRING, defaultValue: 'txt savefile' } } }, { opcode: 'askUserForFileOfTypeAsDataUri', text: 'ask user for a data uri file of type [FILE_TYPE]', disableMonitor: true, blockType: BlockType.REPORTER, arguments: { FILE_TYPE: { type: ArgumentType.STRING, defaultValue: 'png' } } }, { opcode: 'downloadFile', text: 'download content [FILE_CONTENT] as file name [FILE_NAME]', blockType: BlockType.COMMAND, arguments: { FILE_CONTENT: { type: ArgumentType.STRING, defaultValue: 'Hello!' }, FILE_NAME: { type: ArgumentType.STRING, defaultValue: 'text.txt' } } }, { opcode: 'downloadFileDataUri', text: 'download data uri [FILE_CONTENT] as file name [FILE_NAME]', blockType: BlockType.COMMAND, arguments: { FILE_CONTENT: { type: ArgumentType.STRING, defaultValue: 'data:image/png;base64,' }, FILE_NAME: { type: ArgumentType.STRING, defaultValue: 'content.png' } } }, { opcode: 'downloadFileBuffer', text: 'download array buffer [FILE_CONTENT] as file name [FILE_NAME]', blockType: BlockType.COMMAND, arguments: { FILE_CONTENT: { type: ArgumentType.STRING, defaultValue: '[]' }, FILE_NAME: { type: ArgumentType.STRING, defaultValue: 'data.bin' } } } ] }; } isFileReaderSupported () { return (window.FileReader !== null) && (window.document !== null); } dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); } __askUserForFile (acceptTypes) { try { return new Promise(resolve => { const fileReader = new FileReader(); fileReader.onload = e => { resolve(e.target.result); }; const input = document.createElement("input"); input.type = "file"; if (acceptTypes !== null) { input.accept = acceptTypes; } input.style.display = "none"; document.body.append(input); input.onchange = () => { const file = input.files[0]; if (!file) { resolve(""); return; } fileReader.readAsText(file); input.remove(); }; input.onblur = () => { input.onchange(); }; input.focus(); input.click(); }); } catch (e) { return; } } __askUserForFilearraybuffer (acceptTypes) { try { return new Promise(resolve => { const fileReader = new FileReader(); fileReader.onload = e => { resolve(JSON.stringify(BufferStuff.bufferToArray(e.target.result))); }; const input = document.createElement("input"); input.type = "file"; if (acceptTypes !== null) { input.accept = acceptTypes; } input.style.display = "none"; document.body.append(input); input.onchange = () => { const file = input.files[0]; if (!file) { resolve(""); return; } fileReader.readAsArrayBuffer(file); input.remove(); }; input.onblur = () => { input.onchange(); }; input.focus(); input.click(); }); } catch (e) { return; } } __askUserForFiledatauri (acceptTypes) { try { return new Promise(resolve => { const fileReader = new FileReader(); fileReader.onload = e => { resolve(e.target.result); }; const input = document.createElement("input"); input.type = "file"; if (acceptTypes !== null) { input.accept = acceptTypes; } input.style.display = "none"; document.body.append(input); input.onchange = () => { const file = input.files[0]; if (!file) { resolve(""); return; } fileReader.readAsDataURL(file); input.remove(); }; input.onblur = () => { input.onchange(); }; input.focus(); input.click(); }); } catch (e) { return; } } askUserForFileOfType (args) { const fileTypesAllowed = []; const input = args.FILE_TYPE .toLowerCase() .replace(/.,/gmi, ""); if (input === "any") return this.__askUserForFile(null); input.split(" ").forEach(type => { fileTypesAllowed.push(`.${type}`); }); return this.__askUserForFile(fileTypesAllowed.join(","), false); } askUserForFileOfTypeAsArrayBuffer (args) { const fileTypesAllowed = []; const input = args.FILE_TYPE .toLowerCase() .replace(/.,/gmi, ""); if (input === "any") return this.__askUserForFilearraybuffer(null); input.split(" ").forEach(type => { fileTypesAllowed.push(`.${type}`); }); return this.__askUserForFilearraybuffer(fileTypesAllowed.join(",")); } askUserForFileOfTypeAsDataUri (args) { const fileTypesAllowed = []; const input = args.FILE_TYPE .toLowerCase() .replace(/.,/gmi, ""); if (input === "any") return this.__askUserForFiledatauri(null); input.split(" ").forEach(type => { fileTypesAllowed.push(`.${type}`); }); return this.__askUserForFiledatauri(fileTypesAllowed.join(",")); } downloadFile (args, _, __, downloadArray, downloadBase64) { let content = ""; let fileName = "text.txt"; content = String(args.FILE_CONTENT) || content; fileName = String(args.FILE_NAME) || fileName; const array = validateArray(args.FILE_CONTENT); if (array.isValid && downloadArray) { content = BufferStuff.arrayToBuffer(array.array); } let blob; if (downloadBase64) { blob = this.dataURLtoBlob(content); } else { blob = new Blob([content]); } const a = document.createElement("a"); a.style.display = "none"; document.body.append(a); const url = window.URL.createObjectURL(blob); a.href = url; a.download = fileName; a.click(); window.URL.revokeObjectURL(url); a.remove(); } downloadFileDataUri(args) { return this.downloadFile(args, null, null, false, true); } downloadFileBuffer(args) { return this.downloadFile(args, null, null, true, false); } } module.exports = JgFilesBlocks;