Spaces:
Runtime error
Runtime error
| const formatMessage = require('format-message'); | |
| const BlockType = require('../../extension-support/block-type'); | |
| const ArgumentType = require('../../extension-support/argument-type'); | |
| const ProjectPermissionManager = require('../../util/project-permissions'); | |
| const SandboxRunner = require('../../util/sandboxed-javascript-runner'); | |
| const beatgammit = { | |
| deflate: require('./beatgammit-deflate'), | |
| inflate: require('./beatgammit-inflate') | |
| }; | |
| const { | |
| validateArray | |
| } = require('../../util/json-block-utilities'); | |
| const ArrayBufferUtil = require('../../util/array buffer'); | |
| const BufferParser = new ArrayBufferUtil(); | |
| const Cast = require('../../util/cast'); | |
| // const Cast = require('../../util/cast'); | |
| const warningIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC8SURBVDhPpZPBDYMwDEWhJw4MQzdgG0bi0APDlHuPZRv6X2xUaqJWpE8y2Pk/JkRJFVnXtVOMiqdig5yxzm1HJDZu+gWexqcZDCjuqHtcRo/gfTdRkf2yy7kGMG4i/5wlGYSXObqL9MFsRQw06C0voq9ZhxcHasH7m4cV/AUNFkuLWGgwW17EzB5wPB9Wn+aanmoysVGRJAovI5PLydAqzh7l1mWDAUV2JQE8n5P3SORo3xTxOjMWrnNVvQChGZRpEqnWPQAAAABJRU5ErkJggg=="; | |
| /** | |
| * Class for Prism blocks | |
| * @constructor | |
| */ | |
| class JgPrismBlocks { | |
| constructor(runtime) { | |
| /** | |
| * The runtime instantiating this block package. | |
| * @type {Runtime} | |
| */ | |
| this.runtime = runtime; | |
| this.audioPlayer = new Audio(); | |
| this.isJSPermissionGranted = false; | |
| this.isCameraScreenshotEnabled = false; | |
| this.mouseScrollDelta = { x: 0, y: 0, z: 0 }; | |
| addEventListener("wheel", e => { | |
| this.mouseScrollDelta.x = e.deltaX; | |
| this.mouseScrollDelta.y = e.deltaY; | |
| this.mouseScrollDelta.z = e.deltaZ; | |
| }); | |
| setInterval(() => { | |
| this.mouseScrollDelta = { x: 0, y: 0, z: 0 }; | |
| }, 65); | |
| this.encodeCharacterLength = 6; | |
| } | |
| /** | |
| * dummy function for reseting user provided permisions when a save is loaded | |
| */ | |
| deserialize() { | |
| this.isJSPermissionGranted = false; | |
| this.isCameraScreenshotEnabled = false; | |
| } | |
| /** | |
| * @returns {object} metadata for this extension and its blocks. | |
| */ | |
| getInfo() { | |
| return { | |
| id: 'jgPrism', | |
| name: 'Prism', | |
| color1: '#BC7FFF', | |
| color2: '#AD66FF', | |
| blocks: [ | |
| { | |
| opcode: 'playAudioFromUrl', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.playAudioFromUrl', | |
| default: 'play audio from [URL]', | |
| description: 'Plays sound from a URL.' | |
| }), | |
| blockType: BlockType.COMMAND, | |
| hideFromPalette: true, | |
| arguments: { | |
| URL: { | |
| type: ArgumentType.STRING, | |
| defaultValue: 'https://extensions.turbowarp.org/meow.mp3' | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'setAudioToLooping', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.setAudioToLooping', | |
| default: 'set audio to loop', | |
| description: 'Sets the audio to be looping.' | |
| }), | |
| hideFromPalette: true, | |
| blockType: BlockType.COMMAND | |
| }, | |
| { | |
| opcode: 'setAudioToNotLooping', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.setAudioToNotLooping', | |
| default: 'set audio to not loop', | |
| description: 'Sets the audio to not be looping.' | |
| }), | |
| hideFromPalette: true, | |
| blockType: BlockType.COMMAND | |
| }, | |
| { | |
| opcode: 'pauseAudio', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.pauseAudio', | |
| default: 'pause audio', | |
| description: 'Pauses the audio player.' | |
| }), | |
| hideFromPalette: true, | |
| blockType: BlockType.COMMAND | |
| }, | |
| { | |
| opcode: 'playAudio', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.playAudio', | |
| default: 'resume audio', | |
| description: 'Resumes the audio player.' | |
| }), | |
| hideFromPalette: true, | |
| blockType: BlockType.COMMAND | |
| }, | |
| { | |
| opcode: 'setAudioPlaybackSpeed', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.setAudioPlaybackSpeed', | |
| default: 'set audio speed to [SPEED]%', | |
| description: 'Sets the speed of the audio player.' | |
| }), | |
| hideFromPalette: true, | |
| blockType: BlockType.COMMAND, | |
| arguments: { | |
| SPEED: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 100 | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'getAudioPlaybackSpeed', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.getAudioPlaybackSpeed', | |
| default: 'audio speed', | |
| description: 'Block that returns the playback speed of the audio player.' | |
| }), | |
| hideFromPalette: true, | |
| disableMonitor: false, | |
| blockType: BlockType.REPORTER | |
| }, | |
| { | |
| opcode: 'setAudioPosition', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.setAudioPosition', | |
| default: 'set audio position to [POSITION] seconds', | |
| description: 'Sets the position of the current audio in the audio player.' | |
| }), | |
| blockType: BlockType.COMMAND, | |
| hideFromPalette: true, | |
| arguments: { | |
| POSITION: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 5 | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'getAudioPosition', | |
| text: 'audio position', | |
| disableMonitor: false, | |
| hideFromPalette: true, | |
| blockType: BlockType.REPORTER | |
| }, | |
| { | |
| opcode: 'setAudioVolume', | |
| text: formatMessage({ | |
| id: 'jgPrism.blocks.setAudioVolume', | |
| default: 'set audio volume to [VOLUME]%', | |
| description: 'Sets the volume of the current audio in the audio player.' | |
| }), | |
| blockType: BlockType.COMMAND, | |
| hideFromPalette: true, | |
| arguments: { | |
| VOLUME: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 100 | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'getAudioVolume', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.getAudioVolume', | |
| default: 'audio volume', | |
| description: 'Block that returns the volume of the audio player.' | |
| }), | |
| disableMonitor: false, | |
| hideFromPalette: true, | |
| blockType: BlockType.REPORTER | |
| }, | |
| { | |
| blockType: BlockType.LABEL, | |
| text: "Data URIs" | |
| }, | |
| { | |
| opcode: 'screenshotStage', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.screenshotStage', | |
| default: 'screenshot the stage', | |
| description: 'Block that screenshots the stage and returns a Data URI of it.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true | |
| }, | |
| { | |
| opcode: 'dataUriOfCostume', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.dataUriOfCostume', | |
| default: 'data url of costume #[INDEX]', | |
| description: 'Block that returns a Data URI of the costume at the index.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| // these blocks will be replaced in the future | |
| // hideFromPalette: true, | |
| arguments: { | |
| INDEX: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: "1" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'dataUriFromImageUrl', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.dataUriFromImageUrl', | |
| default: 'data url of image at url: [URL]', | |
| description: 'Block that returns a Data URI of the content fetched from the URL.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| // these blocks will be replaced in the future | |
| // hideFromPalette: true, | |
| arguments: { | |
| URL: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "url" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'dataUriFromArrayBuffer', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.dataUriFromArrayBuffer', | |
| default: 'convert array buffer [BUFFER] to data url', | |
| description: 'Block that returns a Data URI from an array buffer.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| arguments: { | |
| BUFFER: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "[72,101,108,108,111]" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'arrayBufferFromDataUri', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.arrayBufferFromDataUri', | |
| default: 'convert data url [URL] to array buffer', | |
| description: 'Block that returns an array buffer from a Data URL.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| arguments: { | |
| URL: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "data:text/plain;base64,SGVsbG8=" | |
| } | |
| } | |
| }, | |
| // { | |
| // blockType: BlockType.LABEL, | |
| // text: "More Mouse Inputs" | |
| // }, | |
| { | |
| opcode: 'currentMouseScrollX', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.currentMouseScrollX', | |
| default: 'mouse scroll x', | |
| description: 'im too lazy to write these anymore tbh' | |
| }), | |
| disableMonitor: false, | |
| hideFromPalette: true, | |
| blockIconURI: warningIcon, | |
| blockType: BlockType.REPORTER | |
| }, | |
| { | |
| opcode: 'currentMouseScroll', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.currentMouseScroll', | |
| default: 'mouse scroll y', | |
| description: 'im too lazy to write these anymore tbh' | |
| }), | |
| disableMonitor: false, | |
| hideFromPalette: true, | |
| blockIconURI: warningIcon, | |
| blockType: BlockType.REPORTER | |
| }, | |
| { | |
| opcode: 'currentMouseScrollZ', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.currentMouseScrollZ', | |
| default: 'mouse scroll z', | |
| description: 'im too lazy to write these anymore tbh' | |
| }), | |
| disableMonitor: false, | |
| hideFromPalette: true, | |
| blockIconURI: warningIcon, | |
| blockType: BlockType.REPORTER | |
| }, | |
| { | |
| blockType: BlockType.LABEL, | |
| text: "Base64" | |
| }, | |
| { | |
| opcode: 'base64Encode', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.base64Encode', | |
| default: 'base64 encode [TEXT]', | |
| description: 'Block that encodes and returns the result of it.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| arguments: { | |
| TEXT: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "abc" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'base64Decode', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.base64Decode', | |
| default: 'base64 decode [TEXT]', | |
| description: 'Block that decodes and returns the result of it.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| arguments: { | |
| TEXT: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "YWJj" | |
| } | |
| } | |
| }, | |
| // { | |
| // blockType: BlockType.LABEL, | |
| // text: "String Character Codes" | |
| // }, | |
| { | |
| opcode: 'fromCharacterCodeString', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.fromCharacterCodeString', | |
| default: 'character from character code [TEXT]', | |
| description: 'Block that decodes and returns the result of it.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| hideFromPalette: true, | |
| blockIconURI: warningIcon, | |
| arguments: { | |
| TEXT: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 97 | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'toCharacterCodeString', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.toCharacterCodeString', | |
| default: 'character code of [TEXT]', | |
| description: 'Block that encodes and returns the result of it.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| hideFromPalette: true, | |
| blockIconURI: warningIcon, | |
| arguments: { | |
| TEXT: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "a" | |
| } | |
| } | |
| }, | |
| "---", | |
| "---", | |
| { | |
| blockType: BlockType.LABEL, | |
| text: "JS Deflate by BeatGammit" | |
| }, | |
| { | |
| opcode: 'lib_deflate_deflateArray', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.lib_deflate_deflateArray', | |
| default: 'deflate [ARRAY]', | |
| description: 'abc' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| arguments: { | |
| ARRAY: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "[]" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'lib_deflate_inflateArray', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.lib_deflate_inflateArray', | |
| default: 'inflate [ARRAY]', | |
| description: 'abc' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| arguments: { | |
| ARRAY: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "[]" | |
| } | |
| } | |
| }, | |
| { | |
| blockType: BlockType.LABEL, | |
| text: "Numerical Encoding by cs2627883" | |
| }, | |
| { | |
| opcode: 'NumericalEncode', | |
| blockType: BlockType.REPORTER, | |
| text: 'encode [DATA] to number', | |
| arguments: { | |
| DATA: { | |
| type: ArgumentType.STRING, | |
| defaultValue: 'Hello!' | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'NumericalDecode', | |
| blockType: BlockType.REPORTER, | |
| text: 'decode [ENCODED] from number', | |
| arguments: { | |
| ENCODED: { | |
| type: ArgumentType.STRING, | |
| defaultValue: '000072000101000108000108000111000033' | |
| } | |
| } | |
| }, | |
| // "---", | |
| // { | |
| // blockType: BlockType.LABEL, | |
| // text: "Deprecated blocks" | |
| // }, | |
| // "---", | |
| // { | |
| // blockType: BlockType.LABEL, | |
| // text: "Don't use any of the blocks below." | |
| // }, | |
| // { | |
| // blockType: BlockType.LABEL, | |
| // text: "They will be removed soon." | |
| // }, | |
| // "---", | |
| // { | |
| // blockType: BlockType.LABEL, | |
| // text: "(Deprecated) JavaScript" | |
| // }, | |
| { | |
| opcode: 'evaluate', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.evaluate', | |
| default: 'eval [JAVASCRIPT]', | |
| description: 'Block that runs JavaScript code.' | |
| }), | |
| blockType: BlockType.COMMAND, | |
| blockIconURI: warningIcon, | |
| hideFromPalette: true, | |
| arguments: { | |
| JAVASCRIPT: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "console.log('Hello!')" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'evaluate2', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.evaluate2', | |
| default: 'eval [JAVASCRIPT]', | |
| description: 'Block that runs JavaScript code and returns the result of it.' | |
| }), | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| blockIconURI: warningIcon, | |
| hideFromPalette: true, | |
| arguments: { | |
| JAVASCRIPT: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "Math.random()" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'evaluate3', | |
| text: formatMessage({ | |
| id: 'jgRuntime.blocks.evaluate3', | |
| default: 'eval [JAVASCRIPT]', | |
| description: 'Block that runs JavaScript code.' | |
| }), | |
| blockType: BlockType.HAT, | |
| blockIconURI: warningIcon, | |
| hideFromPalette: true, | |
| arguments: { | |
| JAVASCRIPT: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "Math.round(Math.random()) == 1" | |
| } | |
| } | |
| } | |
| ] | |
| }; | |
| } | |
| playAudioFromUrl(args) { | |
| if (!this.audioPlayer) this.audioPlayer = new Audio(); | |
| this.audioPlayer.pause(); | |
| this.audioPlayer.src = `${args.URL}`; | |
| this.audioPlayer.currentTime = 0; | |
| this.audioPlayer.play(); | |
| } | |
| setAudioToLooping() { | |
| this.audioPlayer.loop = true; | |
| } | |
| setAudioToNotLooping() { | |
| this.audioPlayer.loop = false; | |
| } | |
| pauseAudio() { | |
| this.audioPlayer.pause(); | |
| } | |
| playAudio() { | |
| this.audioPlayer.play(); | |
| } | |
| setAudioPlaybackSpeed(args) { | |
| this.audioPlayer.playbackRate = (isNaN(Number(args.SPEED)) ? 100 : Number(args.SPEED)) / 100; | |
| } | |
| getAudioPlaybackSpeed() { | |
| return this.audioPlayer.playbackRate * 100; | |
| } | |
| setAudioPosition(args) { | |
| this.audioPlayer.currentTime = isNaN(Number(args.POSITION)) ? 0 : Number(args.POSITION); | |
| } | |
| getAudioPosition() { | |
| return this.audioPlayer.currentTime; | |
| } | |
| setAudioVolume(args) { | |
| this.audioPlayer.volume = (isNaN(Number(args.VOLUME)) ? 100 : Number(args.VOLUME)) / 100; | |
| } | |
| getAudioVolume() { | |
| return this.audioPlayer.volume * 100; | |
| } | |
| // eslint-disable-next-line no-unused-vars | |
| evaluate(args, util, realBlockInfo) { | |
| return new Promise((resolve, reject) => { | |
| // if (!(this.isJSPermissionGranted)) { | |
| // this.isJSPermissionGranted = ProjectPermissionManager.RequestPermission("javascript"); | |
| // if (!this.isJSPermissionGranted) return; | |
| // } | |
| // // otherwise | |
| SandboxRunner.execute(String(args.JAVASCRIPT)).then(result => { | |
| if (!result.success) { | |
| alert(result.value); | |
| console.error(result.value); | |
| return; | |
| } | |
| resolve(result.value) | |
| }) | |
| }) | |
| } | |
| // eslint-disable-next-line no-unused-vars | |
| evaluate2(args, util, realBlockInfo) { | |
| return new Promise((resolve, reject) => { | |
| // if (!(this.isJSPermissionGranted)) { | |
| // this.isJSPermissionGranted = ProjectPermissionManager.RequestPermission("javascript"); | |
| // if (!this.isJSPermissionGranted) return ""; | |
| // } | |
| // // otherwise | |
| SandboxRunner.execute(String(args.JAVASCRIPT)).then(result => { | |
| if (!result.success) { | |
| console.error(result.value); | |
| } | |
| resolve(result.value) | |
| }) | |
| // let result = ""; | |
| // try { | |
| // // eslint-disable-next-line no-eval | |
| // result = eval(String(args.JAVASCRIPT)); | |
| // } catch (e) { | |
| // result = e; | |
| // console.error(e); | |
| // } | |
| // return result; | |
| // return ""; | |
| }) | |
| } | |
| // eslint-disable-next-line no-unused-vars | |
| evaluate3(args, util, realBlockInfo) { | |
| return new Promise((resolve, reject) => { | |
| SandboxRunner.execute(String(args.JAVASCRIPT)).then(result => { | |
| if (!result.success) { | |
| console.error(result.value); | |
| } | |
| resolve(result.value === true) | |
| }) | |
| }) | |
| // if (!(this.isJSPermissionGranted)) { | |
| // this.isJSPermissionGranted = ProjectPermissionManager.RequestPermission("javascript"); | |
| // if (!this.isJSPermissionGranted) return false; | |
| // } | |
| // // otherwise | |
| // let result = true; | |
| // try { | |
| // // eslint-disable-next-line no-eval | |
| // result = eval(String(args.JAVASCRIPT)); | |
| // } catch (e) { | |
| // result = false; | |
| // console.error(e); | |
| // } | |
| // // // otherwise | |
| // return result === true; | |
| // return false; | |
| } | |
| screenshotStage() { | |
| // should we look for an external canvas | |
| if (this.runtime.prism_screenshot_checkForExternalCanvas) { | |
| // if so, does one exist (this will check for more than 1 in the future) | |
| if (this.runtime.prism_screenshot_externalCanvas) { | |
| // we dont need to check camera permissions since external canvases | |
| // will never have the ability to get camera data | |
| return this.runtime.prism_screenshot_externalCanvas.toDataURL(); | |
| } | |
| } | |
| // DO NOT REMOVE, USER HAS NOT GIVEN PERMISSION TO SAVE CAMERA IMAGES. | |
| if (this.runtime.ext_videoSensing || this.runtime.ioDevices.video.provider.enabled) { | |
| // user's camera is on, ask for permission to take a picture of them | |
| if (!(this.isCameraScreenshotEnabled)) { | |
| this.isCameraScreenshotEnabled = ProjectPermissionManager.RequestPermission("cameraPictures"); | |
| if (!this.isCameraScreenshotEnabled) return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAMSURBVBhXY/j//z8ABf4C/qc1gYQAAAAASUVORK5CYII="; // 1 pixel of white | |
| } | |
| } | |
| return new Promise(resolve => { | |
| vm.renderer.requestSnapshot(uri => { | |
| resolve(uri); | |
| }); | |
| }); | |
| } | |
| dataUriOfCostume(args, util) { | |
| const index = Number(args.INDEX); | |
| if (isNaN(index)) return ""; | |
| if (index < 1) return ""; | |
| const target = util.target; | |
| // eslint-disable-next-line no-undefined | |
| if (target.sprite.costumes[index - 1] === undefined || target.sprite.costumes[index - 1] === null) return ""; | |
| const dataURI = target.sprite.costumes[index - 1].asset.encodeDataURI(); | |
| return String(dataURI); | |
| } | |
| dataUriFromImageUrl(args) { | |
| return new Promise(resolve => { | |
| if (window && !window.FileReader) return resolve(""); | |
| if (window && !window.fetch) return resolve(""); | |
| fetch(`https://api.allorigins.win/raw?url=${encodeURIComponent(String(args.URL))}`).then(r => { | |
| r.blob().then(blob => { | |
| const reader = new FileReader(); | |
| reader.onload = e => { | |
| resolve(e.target.result); | |
| }; | |
| reader.readAsDataURL(blob); | |
| }) | |
| .catch(() => { | |
| resolve(""); | |
| }); | |
| }) | |
| .catch(() => { | |
| resolve(""); | |
| }); | |
| }); | |
| } | |
| dataUriFromArrayBuffer(args) { | |
| const array = validateArray(args.BUFFER); | |
| if (!array.isValid) return 'data:text/plain;base64,'; | |
| const buffer = BufferParser.arrayToBuffer(array.array); | |
| let binary = ''; | |
| let bytes = new Uint8Array(buffer); | |
| let len = bytes.byteLength; | |
| for (let i = 0; i < len; i++) { | |
| binary += String.fromCharCode(bytes[i]); | |
| } | |
| // use "application/octet-stream", we have no idea what the buffer actually contains | |
| return `data:application/octet-stream;base64,${btoa(binary)}`; | |
| } | |
| arrayBufferFromDataUri(args) { | |
| const dataUrl = Cast.toString(args.URL); | |
| return new Promise((resolve) => { | |
| fetch(dataUrl).then(res => { | |
| res.arrayBuffer().then(buffer => { | |
| const array = BufferParser.bufferToArray(buffer); | |
| resolve(JSON.stringify(array)); | |
| }).catch(() => { | |
| resolve('[]'); | |
| }); | |
| }).catch(() => { | |
| resolve('[]'); | |
| }); | |
| }); | |
| } | |
| currentMouseScrollX() { | |
| return this.mouseScrollDelta.x; | |
| } | |
| currentMouseScroll() { | |
| return this.mouseScrollDelta.y; | |
| } | |
| currentMouseScrollZ() { | |
| return this.mouseScrollDelta.z; | |
| } | |
| base64Encode(args) { | |
| let result = ""; | |
| try { | |
| result = btoa(String(args.TEXT)); | |
| } catch { | |
| // what a shame | |
| } | |
| return result; | |
| } | |
| base64Decode(args) { | |
| let result = ""; | |
| try { | |
| result = atob(String(args.TEXT)); | |
| } catch { | |
| // what a shame | |
| } | |
| return result; | |
| } | |
| fromCharacterCodeString(args) { | |
| return String.fromCharCode(args.TEXT); | |
| } | |
| toCharacterCodeString(args) { | |
| return String(args.TEXT).charCodeAt(0); | |
| } | |
| lib_deflate_deflateArray(args) { | |
| const array = validateArray(args.ARRAY).array; | |
| return JSON.stringify(beatgammit.deflate(array)); | |
| } | |
| lib_deflate_inflateArray(args) { | |
| const array = validateArray(args.ARRAY).array; | |
| return JSON.stringify(beatgammit.inflate(array)); | |
| } | |
| NumericalEncode(args) { | |
| const toencode = String(args.DATA); | |
| let encoded = ""; | |
| for (let i = 0; i < toencode.length; ++i) { | |
| // Get char code of character | |
| let encodedchar = String(toencode.charCodeAt(i)); | |
| // Pad encodedchar with 0s to ensure all encodedchars are the same length | |
| encodedchar = "0".repeat(this.encodeCharacterLength - encodedchar.length) + encodedchar; | |
| encoded += encodedchar; | |
| } | |
| return encoded; | |
| } | |
| NumericalDecode(args) { | |
| const todecode = String(args.ENCODED); | |
| if (todecode == "") { | |
| return ""; | |
| } | |
| let decoded = ""; | |
| // Create regex to split by char length | |
| const regex = new RegExp('.{1,' + this.encodeCharacterLength + '}', 'g'); | |
| // Split into array of characters | |
| let encodedchars = todecode.match(regex); | |
| for (let i = 0; i < encodedchars.length; i++) { | |
| // Get character from char code | |
| let decodedchar = String.fromCharCode(encodedchars[i]); | |
| decoded += decodedchar; | |
| } | |
| return decoded; | |
| } | |
| } | |
| module.exports = JgPrismBlocks; | |