From f5b75f1b1f59cba45af7cee36de47ea8e5ac581c Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 30 Jul 2023 23:44:25 -0700 Subject: [PATCH 01/46] Better Input Extension Adds various blocks for custom CSS inputs. Focused on remodeling the ask () block. --- extensions/SharkPool/Better Input | 688 ++++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) create mode 100644 extensions/SharkPool/Better Input diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input new file mode 100644 index 0000000000..71d28cf9e0 --- /dev/null +++ b/extensions/SharkPool/Better Input @@ -0,0 +1,688 @@ +/* +* This extension was made by SharkPool +* Version 1.4 (Exit and Enter Effect Blocks) +* Do NOT delete these comments +*/ + +(function(Scratch) { + 'use strict'; + + if (!Scratch.extensions.unsandboxed) { + throw new Error('Better Input must run unsandboxed'); + } + + const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=='; + + const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; + + const formatIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; + + const colorIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=='; + + const effectIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; + + class BetterInputSP { + constructor() { + this.isWaitingForInput = false; + this.userInput = null; + this.fontSize = '14px'; + this.questionColor = '#000000'; + this.inputColor = '#000000'; + this.textBoxColor = '#ffffff'; + this.inputBackgroundColor = '#ffffff'; + this.inputOutlineColor = '#000000'; + this.textAlign = 'left'; + this.fontFamily = 'Arial'; // Default font family (will add more fonts in a later update) + this.showCancelButton = true; + this.submitButtonText = 'OK'; + this.cancelButtonText = 'Cancel'; + this.submitButtonColor = '#0074D9'; + this.cancelButtonColor = '#d9534f'; + this.textBoxBorderRadius = 5; + this.cancelButtonBorderRadius = 5; + this.submitButtonBorderRadius = 5; + this.inputBoxRadius = 4; + this.isInputEnabled = true; + this.submitButtonTextColor = '#ffffff'; + this.cancelButtonTextColor = '#ffffff'; + this.textBoxX = 0; + this.textBoxY = 0; + this.askBoxCount = 0; + this.maxBoxCount = 1; + } + + getInfo() { + return { + id: 'BetterInputSP', + name: 'Better Input', + color1: '#9400ff', + menuIconURI, + blockIconURI, + blocks: [ + { + blockType: Scratch.BlockType.LABEL, + text: 'Text Blocks', + }, + { + opcode: 'askAndWait', + blockType: Scratch.BlockType.COMMAND, + text: 'ask [question] and wait', + arguments: { + question: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'What is your name?', + }, + }, + }, + { + opcode: 'askAndWaitForInput', + blockType: Scratch.BlockType.REPORTER, + text: 'ask [question] and wait', + arguments: { + question: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'What is your name?', + }, + }, + }, + { + opcode: 'getUserInput', + blockType: Scratch.BlockType.REPORTER, + text: 'user input', + }, + { + opcode: "removeAskBoxes", + blockType: Scratch.BlockType.COMMAND, + text: "remove all ask boxes", + }, + { + opcode: 'setFontSize', + blockType: Scratch.BlockType.COMMAND, + text: 'set font size to [SIZE]', + arguments: { + SIZE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 14, + }, + }, + }, + { + opcode: 'setSubmitButtonText', + blockType: Scratch.BlockType.COMMAND, + text: 'set submit button text to [TEXT]', + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'OK', + }, + }, + }, + { + opcode: 'setCancelButtonText', + blockType: Scratch.BlockType.COMMAND, + text: 'set cancel button text to [TEXT]', + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'Cancel', + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: 'Formatting', + }, + { + opcode: 'setTextAlignment', + blockType: Scratch.BlockType.COMMAND, + text: 'set text alignment to [ALIGNMENT]', + blockIconURI: formatIcon, + arguments: { + ALIGNMENT: { + type: Scratch.ArgumentType.STRING, + menu: 'alignmentMenu', + defaultValue: 'left', + }, + }, + }, + { + opcode: 'setFontFamily', + blockType: Scratch.BlockType.COMMAND, + text: 'set font to [FONT]', + blockIconURI: formatIcon, + arguments: { + FONT: { + type: Scratch.ArgumentType.STRING, + menu: 'fontMenu', + defaultValue: 'Arial', + }, + }, + }, + { + opcode: 'setInputEnabled', + blockType: Scratch.BlockType.COMMAND, + text: 'set input [INPUT_ACTION]', + blockIconURI: formatIcon, + arguments: { + INPUT_ACTION: { + type: Scratch.ArgumentType.STRING, + menu: 'inputActionMenu', + defaultValue: 'Enable', + }, + }, + }, + { + opcode: 'setCancelButton', + blockType: Scratch.BlockType.COMMAND, + text: 'set cancel button to [ACTION]', + blockIconURI: formatIcon, + arguments: { + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: 'cancelMenu', + defaultValue: 'Enable', + }, + }, + }, + { + opcode: "setBorderRadius", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] border radius to [VALUE]", + blockIconURI: formatIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, + VALUE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + }, + }, + }, + { + opcode: "setPosition", + blockType: Scratch.BlockType.COMMAND, + text: "set textbox position to x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: 'Color Setting', + }, + { + opcode: 'setColorSettings', + blockType: Scratch.BlockType.COMMAND, + text: 'set [COLOR_TYPE] color to [COLOR]', + blockIconURI: colorIcon, + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: 'colorSettingsMenu', + defaultValue: 'Question Color', + }, + COLOR: { + type: Scratch.ArgumentType.COLOR, + defaultValue: '#000000', + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: 'Effects', + }, + { + opcode: 'setEnterEffect', + blockType: Scratch.BlockType.COMMAND, + text: 'set enter effect to [ENTER_EFFECT]', + blockIconURI: effectIcon, + arguments: { + ENTER_EFFECT: { + type: Scratch.ArgumentType.STRING, + menu: 'enterEffectMenu', + defaultValue: 'None', + }, + }, + }, + { + opcode: 'setExitEffect', + blockType: Scratch.BlockType.COMMAND, + text: 'set exit effect to [EXIT_EFFECT]', + blockIconURI: effectIcon, + arguments: { + EXIT_EFFECT: { + type: Scratch.ArgumentType.STRING, + menu: 'exitEffectMenu', + defaultValue: 'None', + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: 'Operations', + }, + { + opcode: 'setMaxBoxCount', + blockType: Scratch.BlockType.COMMAND, + text: 'set max box count to: [MAX]', + blockIconURI: formatIcon, + arguments: { + MAX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1, + }, + }, + }, + { + opcode: 'getBoxCount', + blockType: Scratch.BlockType.REPORTER, + text: 'box count', + }, + { + opcode: 'getMaxCount', + blockType: Scratch.BlockType.REPORTER, + text: 'box limit', + }, + ], + menus: { + alignmentMenu: ['left', 'right', 'center'], + fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive'], + cancelMenu: ['Enable', 'Disable'], + inputActionMenu: ['Enable', 'Disable'], + enterEffectMenu: ['None', 'Fade in', 'Grow'], + exitEffectMenu: ['None', 'Fade out', 'Shrink'], + elementMenu: ['Textbox', 'Input Box', 'Cancel Button', 'Submit Button'], + colorSettingsMenu: ['Question Color', 'Input Color', 'Textbox Color', 'Input Background Color', 'Input Outline Color', 'Submit Button Color', 'Cancel Button Color', 'Submit Button Text Color', 'Cancel Button Text Color'], + }, + }; + } + + setColorSettings(args) { + const colorType = args.COLOR_TYPE; + const colorValue = args.COLOR; + + switch (colorType) { + case 'Question Color': + this.questionColor = colorValue; + break; + case 'Input Color': + this.inputColor = colorValue; + break; + case 'Textbox Color': + this.textBoxColor = colorValue; + break; + case 'Input Background Color': + this.inputBackgroundColor = colorValue; + break; + case 'Input Outline Color': + this.inputOutlineColor = colorValue; + break; + case 'Submit Button Color': + this.submitButtonColor = colorValue; + break; + case 'Cancel Button Color': + this.cancelButtonColor = colorValue; + break; + case 'Submit Button Text Color': + this.submitButtonTextColor = colorValue; + break; + case 'Cancel Button Text Color': + this.cancelButtonTextColor = colorValue; + break; + } + } + + setBorderRadius(args) { + const element = args.ELEMENT; + let value = args.VALUE; + + if (value < 0) { + value = 0; + } + + switch (element) { + case "Textbox": + this.textBoxBorderRadius = value; + break; + case "Cancel Button": + this.cancelButtonBorderRadius = value; + break; + case "Submit Button": + this.submitButtonBorderRadius = value; + break; + case "Input Box": + this.inputBoxRadius = value; + break; + } + } + + setEnterEffect(args) { + const enterEffect = args.ENTER_EFFECT; + switch (enterEffect) { + case 'None': + this.enterEffect = null; + break; + case 'Fade in': + this.enterEffect = 'fadeIn'; + break; + case 'Grow': + this.enterEffect = 'growIn'; + break; + default: + this.enterEffect = null; + break; + } + } + + setExitEffect(args) { + const exitEffect = args.EXIT_EFFECT; + switch (exitEffect) { + case 'None': + this.exitEffect = null; + break; + case 'Fade out': + this.exitEffect = 'fadeOut'; + break; + case 'Shrink': + this.exitEffect = 'shrinkOut'; + break; + default: + this.exitEffect = null; + break; + } + } + + setPosition(args) { + this.textBoxX = args.X; + this.textBoxY = args.Y * -1; + } + + setMaxBoxCount(args) { + this.maxBoxCount = args.MAX; + } + + setFontSize(args) { + this.fontSize = args.SIZE + 'px'; + } + + setTextAlignment(args) { + this.textAlign = args.ALIGNMENT; + } + + setFontFamily(args) { + this.fontFamily = args.FONT; + } + + setCancelButton(args) { + this.showCancelButton = args.ACTION === 'Enable'; + } + + setSubmitButtonText(args) { + this.submitButtonText = args.TEXT; + } + + setCancelButtonText(args) { + this.cancelButtonText = args.TEXT; + } + + setInputEnabled(args) { + this.isInputEnabled = args.INPUT_ACTION === 'Enable'; + } + + askAndWaitForInput(args) { + if (this.askBoxCount < this.maxBoxCount) { + return new Promise((resolve) => { + this.askAndWait(args).then(() => { + resolve(this.getUserInput()); + }); + }); + } + } + + removeAskBoxes() { + const askBoxes = document.querySelectorAll(".ask-box"); + askBoxes.forEach((box) => { + box.parentNode.removeChild(box); + }); + + if (this.askBoxPromise) { + this.askBoxPromise.resolve("removed"); + this.askBoxPromise = null; + } + this.askBoxCount = 0; + this.userInput = 'removed'; + } + + applyEnterEffect(overlay) { + if (this.enterEffect === 'fadeIn') { + overlay.style.opacity = '0'; + overlay.style.transform = 'scale(1)'; + + let currentOpacity = 0; + const step = () => { + currentOpacity += 10; + overlay.style.opacity = `${currentOpacity}%`; + if (currentOpacity < 100) { + requestAnimationFrame(step); + } + }; + requestAnimationFrame(step); + } else if (this.enterEffect === 'growIn') { + overlay.style.opacity = '1'; + overlay.style.transform = 'scale(0)'; + overlay.style.transition = 'opacity 0.3s'; + + let currentScale = 0; + const step = () => { + currentScale += 10; + overlay.style.transform = `scale(${currentScale / 100})`; + if (currentScale < 100) { + requestAnimationFrame(step); + } + }; + requestAnimationFrame(step); + } else { + overlay.style.opacity = '1'; + } + } + + applyExitEffect(overlay) { + if (this.exitEffect === 'fadeOut') { + overlay.style.transition = 'opacity 0.5s'; + + let currentOpacity = 0; + const step = () => { + currentOpacity -= 20; + overlay.style.opacity = `${currentOpacity}%`; + if (currentOpacity <= 100) { + requestAnimationFrame(step); + } else { + document.body.removeChild(overlay); + } + }; + requestAnimationFrame(step); + } else if (this.exitEffect === 'shrinkOut') { + overlay.style.transition = 'transform 0.3s, opacity 0.3s'; + + let currentScale = 100; + const step = () => { + currentScale -= 15; + overlay.style.transform = `scale(${currentScale / 100})`; + if (currentScale > -200) { + requestAnimationFrame(step); + } else { + document.body.removeChild(overlay); + } + }; + requestAnimationFrame(step); + } else { + document.body.removeChild(overlay); + } + } + + askAndWait(args) { + if (this.askBoxCount < this.maxBoxCount) { + const question = args.question; + this.isWaitingForInput = true; + this.userInput = null; + this.askBoxCount++; + if (this.askBoxPromise) { + this.askBoxPromise.resolve("removed"); + } + + this.askBoxPromise = {}; + + return new Promise((resolve) => { + this.askBoxPromise.resolve = resolve; + const overlay = document.createElement('div'); + overlay.classList.add('ask-box'); + overlay.style.position = 'fixed'; + overlay.style.left = `${43 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; + overlay.style.zIndex = "9999"; + overlay.style.backgroundColor = this.textBoxColor; + overlay.style.boxShadow = '0 0 5px rgba(0, 0, 0, 0.3)'; + overlay.style.borderRadius = this.textBoxBorderRadius + 'px'; + overlay.style.padding = '15px'; + overlay.style.fontSize = this.fontSize; + overlay.style.textAlign = this.textAlign; + overlay.style.fontFamily = this.fontFamily; + + const questionText = document.createElement('div'); + questionText.classList.add('question'); + questionText.style.fontSize = this.fontSize; + questionText.style.marginBottom = '10px'; + questionText.style.color = this.questionColor; + questionText.textContent = question; + + const inputField = document.createElement('input'); + inputField.style.display = this.isInputEnabled ? 'block' : 'none'; + inputField.style.width = '94%'; + inputField.style.padding = '5px'; + inputField.style.fontSize = this.fontSize; + inputField.style.color = this.inputColor; + inputField.style.backgroundColor = this.inputBackgroundColor; + inputField.style.border = `1px solid ${this.inputOutlineColor}`; + inputField.style.borderRadius = this.inputBoxRadius + 'px'; + inputField.style.margin = '0 auto'; + inputField.style.textAlign = this.textAlign; + + const submitButton = document.createElement('button'); + submitButton.style.marginTop = '10px'; + submitButton.style.marginRight = '5px'; + submitButton.style.padding = '5px 10px'; + submitButton.style.backgroundColor = this.submitButtonColor; + submitButton.style.color = this.submitButtonTextColor; + submitButton.style.border = 'none'; + submitButton.style.borderRadius = this.submitButtonBorderRadius + 'px'; + submitButton.style.cursor = 'pointer'; + submitButton.textContent = this.submitButtonText; + + submitButton.addEventListener('click', () => { + this.userInput = inputField.value; + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + resolve(); + } + this.askBoxCount--; + resolve(); + }); + + const cancelButton = document.createElement('button'); + cancelButton.style.marginTop = '10px'; + cancelButton.style.padding = '5px 10px'; + cancelButton.style.backgroundColor = this.cancelButtonColor; + cancelButton.style.color = this.cancelButtonTextColor; + cancelButton.style.border = 'none'; + cancelButton.style.borderRadius = this.cancelButtonBorderRadius + 'px'; + cancelButton.style.cursor = 'pointer'; + cancelButton.textContent = this.cancelButtonText; + cancelButton.style.display = this.showCancelButton ? 'inline-block' : 'none'; + + cancelButton.addEventListener('click', () => { + this.userInput = 'cancelled'; + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + resolve(); + } + this.askBoxCount--; + resolve(); + }); + + + overlay.appendChild(questionText); + + if (this.isInputEnabled) { + overlay.appendChild(inputField); + } + + overlay.appendChild(submitButton); + overlay.appendChild(cancelButton); + + document.body.appendChild(overlay); + inputField.focus(); + + if (this.enterEffect) { + this.applyEnterEffect(overlay); + } else { + overlay.style.opacity = '1'; + overlay.style.transform = 'scale(1)'; + } + + const resizeHandler = () => { + if (this.textBoxX !== null && this.textBoxY !== null) { + overlay.style.left = `${50 + this.textBoxX}%`; + overlay.style.top = `${50 + this.textBoxY}%`; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } + }; + + document.addEventListener("fullscreenchange", resizeHandler); + document.addEventListener("webkitfullscreenchange", resizeHandler); + document.addEventListener("mozfullscreenchange", resizeHandler); + document.addEventListener("MSFullscreenChange", resizeHandler); + + overlay.addEventListener("DOMNodeRemoved", () => { + document.removeEventListener("fullscreenchange", resizeHandler); + document.removeEventListener("webkitfullscreenchange", resizeHandler); + document.removeEventListener("mozfullscreenchange", resizeHandler); + document.removeEventListener("MSFullscreenChange", resizeHandler); + }); + }); + } + } + + getUserInput() { + return this.userInput; + } + + getBoxCount() { + return this.askBoxCount; + } + + getMaxCount() { + return this.maxBoxCount; + } +} + + Scratch.extensions.register(new BetterInputSP()); +})(Scratch); From 4882c27449a3fd98656b995dc10222a3f2e68ee2 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:26:17 -0700 Subject: [PATCH 02/46] Update Better Input Fixed some issues --- extensions/SharkPool/Better Input | 53 ++++++++++++++++--------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input index 71d28cf9e0..d829073f72 100644 --- a/extensions/SharkPool/Better Input +++ b/extensions/SharkPool/Better Input @@ -1,6 +1,6 @@ /* * This extension was made by SharkPool -* Version 1.4 (Exit and Enter Effect Blocks) +* Version 1.5 (More Fonts and Changes) * Do NOT delete these comments */ @@ -19,7 +19,7 @@ const colorIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=='; - const effectIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; + const effectIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; class BetterInputSP { constructor() { @@ -161,13 +161,13 @@ { opcode: 'setInputEnabled', blockType: Scratch.BlockType.COMMAND, - text: 'set input [INPUT_ACTION]', + text: 'set input box to [INPUT_ACTION]', blockIconURI: formatIcon, arguments: { INPUT_ACTION: { type: Scratch.ArgumentType.STRING, menu: 'inputActionMenu', - defaultValue: 'Enable', + defaultValue: 'Enabled', }, }, }, @@ -179,8 +179,8 @@ arguments: { ACTION: { type: Scratch.ArgumentType.STRING, - menu: 'cancelMenu', - defaultValue: 'Enable', + menu: 'inputActionMenu', + defaultValue: 'Enabled', }, }, }, @@ -230,7 +230,7 @@ COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: 'colorSettingsMenu', - defaultValue: 'Question Color', + defaultValue: 'Question', }, COLOR: { type: Scratch.ArgumentType.COLOR, @@ -297,13 +297,12 @@ ], menus: { alignmentMenu: ['left', 'right', 'center'], - fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive'], - cancelMenu: ['Enable', 'Disable'], - inputActionMenu: ['Enable', 'Disable'], + fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive', 'Lucida Console', 'Scratch','Arial Black', 'Calibri', 'Consolas', 'Handwriting', 'Marker','Curly', 'Pixel'], + inputActionMenu: ['Enabled', 'Disabled'], enterEffectMenu: ['None', 'Fade in', 'Grow'], exitEffectMenu: ['None', 'Fade out', 'Shrink'], elementMenu: ['Textbox', 'Input Box', 'Cancel Button', 'Submit Button'], - colorSettingsMenu: ['Question Color', 'Input Color', 'Textbox Color', 'Input Background Color', 'Input Outline Color', 'Submit Button Color', 'Cancel Button Color', 'Submit Button Text Color', 'Cancel Button Text Color'], + colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Submit Button', 'Cancel Button', 'Submit Button Text', 'Cancel Button Text'], }, }; } @@ -313,31 +312,31 @@ const colorValue = args.COLOR; switch (colorType) { - case 'Question Color': + case 'Question': this.questionColor = colorValue; break; - case 'Input Color': + case 'Input Text': this.inputColor = colorValue; break; - case 'Textbox Color': + case 'Textbox': this.textBoxColor = colorValue; break; - case 'Input Background Color': + case 'Input Background': this.inputBackgroundColor = colorValue; break; - case 'Input Outline Color': + case 'Input Outline': this.inputOutlineColor = colorValue; break; - case 'Submit Button Color': + case 'Submit Button': this.submitButtonColor = colorValue; break; - case 'Cancel Button Color': + case 'Cancel Button': this.cancelButtonColor = colorValue; break; - case 'Submit Button Text Color': + case 'Submit Button Text': this.submitButtonTextColor = colorValue; break; - case 'Cancel Button Text Color': + case 'Cancel Button Text': this.cancelButtonTextColor = colorValue; break; } @@ -425,7 +424,7 @@ } setCancelButton(args) { - this.showCancelButton = args.ACTION === 'Enable'; + this.showCancelButton = args.ACTION === 'Enabled'; } setSubmitButtonText(args) { @@ -437,7 +436,7 @@ } setInputEnabled(args) { - this.isInputEnabled = args.INPUT_ACTION === 'Enable'; + this.isInputEnabled = args.INPUT_ACTION === 'Enabled'; } askAndWaitForInput(args) { @@ -503,9 +502,9 @@ let currentOpacity = 0; const step = () => { - currentOpacity -= 20; + currentOpacity -= 5; overlay.style.opacity = `${currentOpacity}%`; - if (currentOpacity <= 100) { + if (currentOpacity > -100) { requestAnimationFrame(step); } else { document.body.removeChild(overlay); @@ -552,7 +551,7 @@ overlay.style.top = `${44 + this.textBoxY}%`; overlay.style.zIndex = "9999"; overlay.style.backgroundColor = this.textBoxColor; - overlay.style.boxShadow = '0 0 5px rgba(0, 0, 0, 0.3)'; + overlay.style.boxShadow = '0 0 5px rgba(0, 0, 0, 0.3)'; overlay.style.borderRadius = this.textBoxBorderRadius + 'px'; overlay.style.padding = '15px'; overlay.style.fontSize = this.fontSize; @@ -614,7 +613,9 @@ cancelButton.style.display = this.showCancelButton ? 'inline-block' : 'none'; cancelButton.addEventListener('click', () => { - this.userInput = 'cancelled'; + if (!this.isInputEnabled) { + this.userInput = 'cancelled'; + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); From fc0484d70408d95d90f0ef6d91ea2f71d3c0f783 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Wed, 2 Aug 2023 01:00:41 -0700 Subject: [PATCH 03/46] Update Better Input --- extensions/SharkPool/Better Input | 193 ++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 51 deletions(-) diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input index d829073f72..9a1cbefb75 100644 --- a/extensions/SharkPool/Better Input +++ b/extensions/SharkPool/Better Input @@ -1,6 +1,6 @@ /* * This extension was made by SharkPool -* Version 1.5 (More Fonts and Changes) +* Version 1.6 (More Buttons) * Do NOT delete these comments */ @@ -32,19 +32,29 @@ this.inputBackgroundColor = '#ffffff'; this.inputOutlineColor = '#000000'; this.textAlign = 'left'; - this.fontFamily = 'Arial'; // Default font family (will add more fonts in a later update) + this.fontFamily = 'Arial'; this.showCancelButton = true; - this.submitButtonText = 'OK'; + this.showButton3 = true; + this.showButton4 = true; + this.submitButtonText = 'Submit'; this.cancelButtonText = 'Cancel'; + this.Button3Text = 'Okay'; + this.Button4Text = 'No'; this.submitButtonColor = '#0074D9'; this.cancelButtonColor = '#d9534f'; - this.textBoxBorderRadius = 5; + this.button3Color = '#0074D9'; + this.button4Color = '#d9534f'; this.cancelButtonBorderRadius = 5; this.submitButtonBorderRadius = 5; - this.inputBoxRadius = 4; - this.isInputEnabled = true; + this.button3BorderRadius = 5; + this.button4BorderRadius = 5; this.submitButtonTextColor = '#ffffff'; this.cancelButtonTextColor = '#ffffff'; + this.button3TextColor = '#ffffff'; + this.button4TextColor = '#ffffff'; + this.textBoxBorderRadius = 5; + this.inputBoxRadius = 4; + this.isInputEnabled = true; this.textBoxX = 0; this.textBoxY = 0; this.askBoxCount = 0; @@ -107,24 +117,18 @@ }, }, { - opcode: 'setSubmitButtonText', + opcode: 'setButtonText', blockType: Scratch.BlockType.COMMAND, - text: 'set submit button text to [TEXT]', + text: 'set [BUTTON_MENU] text to [TEXT]', arguments: { - TEXT: { + BUTTON_MENU: { type: Scratch.ArgumentType.STRING, - defaultValue: 'OK', + menu: 'buttonMenu', + defaultValue: 'Button 1', }, - }, - }, - { - opcode: 'setCancelButtonText', - blockType: Scratch.BlockType.COMMAND, - text: 'set cancel button text to [TEXT]', - arguments: { TEXT: { type: Scratch.ArgumentType.STRING, - defaultValue: 'Cancel', + defaultValue: 'Submit', }, }, }, @@ -135,7 +139,7 @@ { opcode: 'setTextAlignment', blockType: Scratch.BlockType.COMMAND, - text: 'set text alignment to [ALIGNMENT]', + text: 'set alignment to [ALIGNMENT]', blockIconURI: formatIcon, arguments: { ALIGNMENT: { @@ -159,24 +163,16 @@ }, }, { - opcode: 'setInputEnabled', + opcode: 'setEnable', blockType: Scratch.BlockType.COMMAND, - text: 'set input box to [INPUT_ACTION]', + text: 'set [ENABLE_MENU] to be [ACTION]', blockIconURI: formatIcon, arguments: { - INPUT_ACTION: { + ENABLE_MENU: { type: Scratch.ArgumentType.STRING, - menu: 'inputActionMenu', - defaultValue: 'Enabled', + menu: 'enableMenu', + defaultValue: 'Input Box', }, - }, - }, - { - opcode: 'setCancelButton', - blockType: Scratch.BlockType.COMMAND, - text: 'set cancel button to [ACTION]', - blockIconURI: formatIcon, - arguments: { ACTION: { type: Scratch.ArgumentType.STRING, menu: 'inputActionMenu', @@ -301,8 +297,10 @@ inputActionMenu: ['Enabled', 'Disabled'], enterEffectMenu: ['None', 'Fade in', 'Grow'], exitEffectMenu: ['None', 'Fade out', 'Shrink'], - elementMenu: ['Textbox', 'Input Box', 'Cancel Button', 'Submit Button'], - colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Submit Button', 'Cancel Button', 'Submit Button Text', 'Cancel Button Text'], + buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4'], + enableMenu: ['Input Box','Button 2', 'Button 3', 'Button 4'], + elementMenu: ['Textbox', 'Input Box', 'Cancel Button', 'Submit Button', 'Button 3', 'Button 4'], + colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Submit Button', 'Cancel Button', 'Button 3', 'Button 4', 'Submit Button Text', 'Cancel Button Text', 'Button 3 Text', 'Button 4 Text'], }, }; } @@ -333,12 +331,24 @@ case 'Cancel Button': this.cancelButtonColor = colorValue; break; + case 'Button 3': + this.button3Color = colorValue; + break; + case 'Button 4': + this.button4Color = colorValue; + break; case 'Submit Button Text': this.submitButtonTextColor = colorValue; break; case 'Cancel Button Text': this.cancelButtonTextColor = colorValue; break; + case 'Button 3 Text': + this.button3TextColor = colorValue; + break; + case 'Button 4 Text': + this.button4TextColor = colorValue; + break; } } @@ -360,6 +370,12 @@ case "Submit Button": this.submitButtonBorderRadius = value; break; + case "Button 3": + this.button3BorderRadius = value; + break; + case "Button 4": + this.button4BorderRadius = value; + break; case "Input Box": this.inputBoxRadius = value; break; @@ -423,20 +439,42 @@ this.fontFamily = args.FONT; } - setCancelButton(args) { - this.showCancelButton = args.ACTION === 'Enabled'; - } - - setSubmitButtonText(args) { - this.submitButtonText = args.TEXT; + setEnable(args) { + const enableMenu = args.ENABLE_MENU; + const action = args.ACTION; + switch (enableMenu) { + case 'Input Box': + this.isInputEnabled = action === 'Enabled'; + break; + case 'Button 2': + this.showCancelButton = action === 'Enabled'; + break; + case 'Button 3': + this.showButton3 = action === 'Enabled'; + break; + case 'Button 4': + this.showButton4 = action === 'Enabled'; + break; + } } - setCancelButtonText(args) { - this.cancelButtonText = args.TEXT; - } - - setInputEnabled(args) { - this.isInputEnabled = args.INPUT_ACTION === 'Enabled'; + setButtonText(args) { + const buttonMenu = args.BUTTON_MENU; + const text = args.TEXT; + switch (buttonMenu) { + case 'Button 1': + this.submitButtonText = text; + break; + case 'Button 2': + this.cancelButtonText = text; + break; + case 'Button 3': + this.Button3Text = text; + break; + case 'Button 4': + this.Button4Text = text; + break; + } } askAndWaitForInput(args) { @@ -547,7 +585,7 @@ const overlay = document.createElement('div'); overlay.classList.add('ask-box'); overlay.style.position = 'fixed'; - overlay.style.left = `${43 + this.textBoxX}%`; + overlay.style.left = `${41 + this.textBoxX}%`; overlay.style.top = `${44 + this.textBoxY}%`; overlay.style.zIndex = "9999"; overlay.style.backgroundColor = this.textBoxColor; @@ -589,7 +627,11 @@ submitButton.textContent = this.submitButtonText; submitButton.addEventListener('click', () => { - this.userInput = inputField.value; + if (this.isInputEnabled) { + this.userInput = inputField.value; + } else { + this.userInput = this.submitButtonText; + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -598,11 +640,11 @@ resolve(); } this.askBoxCount--; - resolve(); }); const cancelButton = document.createElement('button'); cancelButton.style.marginTop = '10px'; + cancelButton.style.marginRight = '5px'; cancelButton.style.padding = '5px 10px'; cancelButton.style.backgroundColor = this.cancelButtonColor; cancelButton.style.color = this.cancelButtonTextColor; @@ -614,7 +656,7 @@ cancelButton.addEventListener('click', () => { if (!this.isInputEnabled) { - this.userInput = 'cancelled'; + this.userInput = this.cancelButtonText; } this.isWaitingForInput = false; if (this.exitEffect) { @@ -624,7 +666,54 @@ resolve(); } this.askBoxCount--; - resolve(); + }); + + const Button3 = document.createElement('button'); + Button3.style.marginTop = '10px'; + Button3.style.marginRight = '5px'; + Button3.style.padding = '5px 10px'; + Button3.style.backgroundColor = this.button3Color; + Button3.style.color = this.button3TextColor; + Button3.style.border = 'none'; + Button3.style.borderRadius = this.button3BorderRadius + 'px'; + Button3.style.cursor = 'pointer'; + Button3.textContent = this.Button3Text; + Button3.style.display = this.showButton3 ? 'inline-block' : 'none'; + + Button3.addEventListener('click', () => { + this.userInput = this.Button3Text; + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + resolve(); + } + this.askBoxCount--; + }); + + const Button4 = document.createElement('button'); + Button4.style.marginTop = '10px'; + Button4.style.marginRight = '5px'; + Button4.style.padding = '5px 10px'; + Button4.style.backgroundColor = this.button4Color; + Button4.style.color = this.button4TextColor; + Button4.style.border = 'none'; + Button4.style.borderRadius = this.button4BorderRadius + 'px'; + Button4.style.cursor = 'pointer'; + Button4.textContent = this.Button4Text; + Button4.style.display = this.showButton4 ? 'inline-block' : 'none'; + + Button4.addEventListener('click', () => { + this.userInput = this.Button4Text; + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + resolve(); + } + this.askBoxCount--; }); @@ -636,6 +725,8 @@ overlay.appendChild(submitButton); overlay.appendChild(cancelButton); + overlay.appendChild(Button3); + overlay.appendChild(Button4); document.body.appendChild(overlay); inputField.focus(); From 2bab521477f556424c94860d78908470a6202748 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Fri, 4 Aug 2023 00:39:53 -0700 Subject: [PATCH 04/46] Update Better Input --- extensions/SharkPool/Better Input | 256 ++++++++++++++++++++++++------ 1 file changed, 211 insertions(+), 45 deletions(-) diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input index 9a1cbefb75..00cf312d29 100644 --- a/extensions/SharkPool/Better Input +++ b/extensions/SharkPool/Better Input @@ -1,6 +1,6 @@ /* * This extension was made by SharkPool -* Version 1.6 (More Buttons) +* Version 1.7 (Emergency DOM fixes, Force Input Block, More Positioning, and Image setting) * Do NOT delete these comments */ @@ -58,7 +58,10 @@ this.textBoxX = 0; this.textBoxY = 0; this.askBoxCount = 0; - this.maxBoxCount = 1; + this.maxBoxCount = 1; + this.forceInput = 'Disabled'; + this.overlayInput = null + this.overlayImage = null } getInfo() { @@ -105,17 +108,6 @@ blockType: Scratch.BlockType.COMMAND, text: "remove all ask boxes", }, - { - opcode: 'setFontSize', - blockType: Scratch.BlockType.COMMAND, - text: 'set font size to [SIZE]', - arguments: { - SIZE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 14, - }, - }, - }, { opcode: 'setButtonText', blockType: Scratch.BlockType.COMMAND, @@ -181,22 +173,21 @@ }, }, { - opcode: "setBorderRadius", + opcode: 'setFontSize', blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] border radius to [VALUE]", + text: 'set font size to [SIZE]', blockIconURI: formatIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - defaultValue: "Textbox", - }, - VALUE: { + SIZE: { type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, + defaultValue: 14, }, }, }, + { + blockType: Scratch.BlockType.LABEL, + text: 'Positioning', + }, { opcode: "setPosition", blockType: Scratch.BlockType.COMMAND, @@ -213,9 +204,37 @@ }, }, }, + { + opcode: "changePosition", + blockType: Scratch.BlockType.COMMAND, + text: "change textbox position by x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + { + opcode: 'getXpos', + blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, + text: 'x position', + }, + { + opcode: 'getYpos', + blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, + text: 'y position', + }, { blockType: Scratch.BlockType.LABEL, - text: 'Color Setting', + text: 'Visual Settings', }, { opcode: 'setColorSettings', @@ -234,6 +253,35 @@ }, }, }, + { + opcode: "setBorderRadius", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] border radius to [VALUE]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, + VALUE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + }, + }, + }, + { + opcode: "setImage", + blockType: Scratch.BlockType.COMMAND, + text: "set background image to [IMAGE]", + blockIconURI: colorIcon, + arguments: { + IMAGE: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'input-url-or-uri-here', + }, + }, + }, { blockType: Scratch.BlockType.LABEL, text: 'Effects', @@ -268,11 +316,22 @@ blockType: Scratch.BlockType.LABEL, text: 'Operations', }, + { + opcode: 'setSubmitEvent', + blockType: Scratch.BlockType.COMMAND, + text: 'set force input to [ENTER]', + arguments: { + ENTER: { + type: Scratch.ArgumentType.STRING, + menu: 'enterMenu', + defaultValue: 'Disabled', + }, + }, + }, { opcode: 'setMaxBoxCount', blockType: Scratch.BlockType.COMMAND, text: 'set max box count to: [MAX]', - blockIconURI: formatIcon, arguments: { MAX: { type: Scratch.ArgumentType.NUMBER, @@ -294,13 +353,14 @@ menus: { alignmentMenu: ['left', 'right', 'center'], fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive', 'Lucida Console', 'Scratch','Arial Black', 'Calibri', 'Consolas', 'Handwriting', 'Marker','Curly', 'Pixel'], + enterMenu: ['Disabled', 'Enter Key', 'Shift + Enter key'], inputActionMenu: ['Enabled', 'Disabled'], enterEffectMenu: ['None', 'Fade in', 'Grow'], exitEffectMenu: ['None', 'Fade out', 'Shrink'], buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4'], enableMenu: ['Input Box','Button 2', 'Button 3', 'Button 4'], - elementMenu: ['Textbox', 'Input Box', 'Cancel Button', 'Submit Button', 'Button 3', 'Button 4'], - colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Submit Button', 'Cancel Button', 'Button 3', 'Button 4', 'Submit Button Text', 'Cancel Button Text', 'Button 3 Text', 'Button 4 Text'], + elementMenu: ['Textbox', 'Input Box', 'Button 1', 'Button 2', 'Button 3', 'Button 4'], + colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Button 1 Text', 'Button 2 Text', 'Button 3 Text', 'Button 4 Text'], }, }; } @@ -318,6 +378,7 @@ break; case 'Textbox': this.textBoxColor = colorValue; + this.overlayImage = null; break; case 'Input Background': this.inputBackgroundColor = colorValue; @@ -325,22 +386,26 @@ case 'Input Outline': this.inputOutlineColor = colorValue; break; - case 'Submit Button': + case 'Button 1': this.submitButtonColor = colorValue; + this.Btn1Image = null; break; - case 'Cancel Button': + case 'Button 2': this.cancelButtonColor = colorValue; + this.Btn2Image = null; break; case 'Button 3': this.button3Color = colorValue; + this.Btn3Image = null; break; case 'Button 4': this.button4Color = colorValue; + this.Btn4Image = null; break; - case 'Submit Button Text': + case 'Button 1 Text': this.submitButtonTextColor = colorValue; break; - case 'Cancel Button Text': + case 'Button 2 Text': this.cancelButtonTextColor = colorValue; break; case 'Button 3 Text': @@ -364,10 +429,10 @@ case "Textbox": this.textBoxBorderRadius = value; break; - case "Cancel Button": + case "Button 1": this.cancelButtonBorderRadius = value; break; - case "Submit Button": + case "Button 2": this.submitButtonBorderRadius = value; break; case "Button 3": @@ -421,6 +486,32 @@ setPosition(args) { this.textBoxX = args.X; this.textBoxY = args.Y * -1; + + + const overlays = document.querySelectorAll(".ask-box"); + overlays.forEach((overlay) => { + this.updateOverlayPosition(overlay); + }); + } + + changePosition(args) { + this.textBoxX = this.textBoxX + args.X; + this.textBoxY = this.textBoxY + args.Y * -1; + + const overlays = document.querySelectorAll(".ask-box"); + overlays.forEach((overlay) => { + this.updateOverlayPosition(overlay); + }); + } + + updateOverlayPosition(overlay) { + if (this.textBoxX !== null && this.textBoxY !== null) { + overlay.style.left = `${41 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } } setMaxBoxCount(args) { @@ -595,6 +686,56 @@ overlay.style.fontSize = this.fontSize; overlay.style.textAlign = this.textAlign; overlay.style.fontFamily = this.fontFamily; + + const overlayImageContainer = document.createElement('div'); + overlayImageContainer.style.background = `url(${this.overlayImage})`; + overlayImageContainer.style.width = '100%'; + overlayImageContainer.style.height = '100%'; + overlayImageContainer.style.position = 'absolute'; + overlayImageContainer.style.top = '0'; + overlayImageContainer.style.left = '0'; + overlayImageContainer.style.zIndex = '-1'; + + if (this.forceInput !== 'Disabled') { + let overlayInput; + + if (this.forceInput === 'Enter Key') { + overlayInput = 'Enter'; + } else { + overlayInput = 'ShiftEnter'; + } + + const handleKeydown = (event) => { + if ( + (overlayInput === 'Enter' && event.key === 'Enter') || + (overlayInput === 'ShiftEnter' && event.shiftKey && event.key === 'Enter') + ) { + this.userInput = inputField.value; + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + + } + resolve(); + this.askBoxCount--; + } + }; + + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === 'childList' && !document.contains(overlay)) { + document.removeEventListener('keydown', handleKeydown); + observer.disconnect(); + } + } + }); + + observer.observe(document.body, { childList: true }); + + document.addEventListener('keydown', handleKeydown); + } const questionText = document.createElement('div'); questionText.classList.add('question'); @@ -637,8 +778,8 @@ this.applyExitEffect(overlay); } else { document.body.removeChild(overlay); - resolve(); } + resolve(); this.askBoxCount--; }); @@ -663,8 +804,8 @@ this.applyExitEffect(overlay); } else { document.body.removeChild(overlay); - resolve(); } + resolve(); this.askBoxCount--; }); @@ -687,8 +828,8 @@ this.applyExitEffect(overlay); } else { document.body.removeChild(overlay); - resolve(); } + resolve(); this.askBoxCount--; }); @@ -711,12 +852,11 @@ this.applyExitEffect(overlay); } else { document.body.removeChild(overlay); - resolve(); } + resolve(); this.askBoxCount--; }); - overlay.appendChild(questionText); if (this.isInputEnabled) { @@ -727,6 +867,7 @@ overlay.appendChild(cancelButton); overlay.appendChild(Button3); overlay.appendChild(Button4); + overlay.appendChild(overlayImageContainer); document.body.appendChild(overlay); inputField.focus(); @@ -740,8 +881,8 @@ const resizeHandler = () => { if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${50 + this.textBoxX}%`; - overlay.style.top = `${50 + this.textBoxY}%`; + overlay.style.left = `${41 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; } else { overlay.style.left = "50%"; overlay.style.top = "50%"; @@ -752,13 +893,22 @@ document.addEventListener("webkitfullscreenchange", resizeHandler); document.addEventListener("mozfullscreenchange", resizeHandler); document.addEventListener("MSFullscreenChange", resizeHandler); - - overlay.addEventListener("DOMNodeRemoved", () => { - document.removeEventListener("fullscreenchange", resizeHandler); - document.removeEventListener("webkitfullscreenchange", resizeHandler); - document.removeEventListener("mozfullscreenchange", resizeHandler); - document.removeEventListener("MSFullscreenChange", resizeHandler); + + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === "childList" && !document.contains(overlay)) { + document.removeEventListener("fullscreenchange", resizeHandler); + document.removeEventListener("webkitfullscreenchange", resizeHandler); + document.removeEventListener("mozfullscreenchange", resizeHandler); + document.removeEventListener("MSFullscreenChange", resizeHandler); + observer.disconnect(); + } + } }); + + observer.observe(document.body, { childList: true }); + document.body.appendChild(overlay); + inputField.focus(); }); } } @@ -774,6 +924,22 @@ getMaxCount() { return this.maxBoxCount; } + + getXpos() { + return this.textBoxX; + } + + getYpos() { + return this.textBoxY; + } + + setSubmitEvent(args) { + this.forceInput = args.ENTER; + } + + setImage(args) { + this.overlayImage = args.IMAGE; + } } Scratch.extensions.register(new BetterInputSP()); From 134c1808fa01f0cf34e23728b75e3f181714d1c8 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 5 Aug 2023 00:14:35 -0700 Subject: [PATCH 05/46] Update Better Input --- extensions/SharkPool/Better Input | 152 +++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 25 deletions(-) diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input index 00cf312d29..b611e164e4 100644 --- a/extensions/SharkPool/Better Input +++ b/extensions/SharkPool/Better Input @@ -1,6 +1,6 @@ /* * This extension was made by SharkPool -* Version 1.7 (Emergency DOM fixes, Force Input Block, More Positioning, and Image setting) +* Version 1.8 (Bug fixes and Dropdown-able Menus) * Do NOT delete these comments */ @@ -40,28 +40,33 @@ this.cancelButtonText = 'Cancel'; this.Button3Text = 'Okay'; this.Button4Text = 'No'; + this.DropdownText = 'Dropdown'; this.submitButtonColor = '#0074D9'; this.cancelButtonColor = '#d9534f'; this.button3Color = '#0074D9'; this.button4Color = '#d9534f'; + this.optionbuttonColor = '#5f5f5f'; this.cancelButtonBorderRadius = 5; this.submitButtonBorderRadius = 5; this.button3BorderRadius = 5; this.button4BorderRadius = 5; + this.optionbuttonBorderRadius = 5; this.submitButtonTextColor = '#ffffff'; this.cancelButtonTextColor = '#ffffff'; this.button3TextColor = '#ffffff'; this.button4TextColor = '#ffffff'; + this.optionbuttonTextColor = '#ffffff'; this.textBoxBorderRadius = 5; this.inputBoxRadius = 4; - this.isInputEnabled = true; + this.isInputEnabled = 'Enabled'; this.textBoxX = 0; this.textBoxY = 0; this.askBoxCount = 0; this.maxBoxCount = 1; this.forceInput = 'Disabled'; - this.overlayInput = null - this.overlayImage = null + this.overlayInput = null; + this.overlayImage = null; + this.optionList = 'Option 1,Option 2,Option 3'; } getInfo() { @@ -124,6 +129,17 @@ }, }, }, + { + opcode: 'setDropdown', + blockType: Scratch.BlockType.COMMAND, + text: 'set dropdown options to array: [DROPDOWN]', + arguments: { + DROPDOWN: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'option 1,option 2,option 3', + }, + }, + }, { blockType: Scratch.BlockType.LABEL, text: 'Formatting', @@ -154,6 +170,19 @@ }, }, }, + { + opcode: 'setInputType', + blockType: Scratch.BlockType.COMMAND, + text: 'set Input Box to be [ACTION]', + blockIconURI: formatIcon, + arguments: { + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: 'inputActionMenu', + defaultValue: 'Enabled', + }, + }, + }, { opcode: 'setEnable', blockType: Scratch.BlockType.COMMAND, @@ -163,11 +192,11 @@ ENABLE_MENU: { type: Scratch.ArgumentType.STRING, menu: 'enableMenu', - defaultValue: 'Input Box', + defaultValue: 'Button 2', }, ACTION: { type: Scratch.ArgumentType.STRING, - menu: 'inputActionMenu', + menu: 'buttonActionMenu', defaultValue: 'Enabled', }, }, @@ -354,13 +383,14 @@ alignmentMenu: ['left', 'right', 'center'], fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive', 'Lucida Console', 'Scratch','Arial Black', 'Calibri', 'Consolas', 'Handwriting', 'Marker','Curly', 'Pixel'], enterMenu: ['Disabled', 'Enter Key', 'Shift + Enter key'], - inputActionMenu: ['Enabled', 'Disabled'], + buttonActionMenu: ['Enabled', 'Disabled'], + inputActionMenu: ['Enabled', 'Disabled', 'Dropdown'], enterEffectMenu: ['None', 'Fade in', 'Grow'], exitEffectMenu: ['None', 'Fade out', 'Shrink'], - buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4'], - enableMenu: ['Input Box','Button 2', 'Button 3', 'Button 4'], - elementMenu: ['Textbox', 'Input Box', 'Button 1', 'Button 2', 'Button 3', 'Button 4'], - colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Button 1 Text', 'Button 2 Text', 'Button 3 Text', 'Button 4 Text'], + buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4', 'Dropdown'], + enableMenu: ['Button 2', 'Button 3', 'Button 4'], + elementMenu: ['Textbox', 'Input Box', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons'], + colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons', 'Button 1 Text', 'Button 2 Text', 'Button 3 Text', 'Button 4 Text', 'Dropdown Text'], }, }; } @@ -388,19 +418,18 @@ break; case 'Button 1': this.submitButtonColor = colorValue; - this.Btn1Image = null; break; case 'Button 2': this.cancelButtonColor = colorValue; - this.Btn2Image = null; break; case 'Button 3': this.button3Color = colorValue; - this.Btn3Image = null; break; case 'Button 4': this.button4Color = colorValue; - this.Btn4Image = null; + break; + case 'Dropdown Buttons': + this.optionbuttonColor = colorValue; break; case 'Button 1 Text': this.submitButtonTextColor = colorValue; @@ -414,6 +443,9 @@ case 'Button 4 Text': this.button4TextColor = colorValue; break; + case 'Dropdown Text': + this.optionButtonTextColor = colorValue; + break; } } @@ -444,6 +476,9 @@ case "Input Box": this.inputBoxRadius = value; break; + case "Dropdown Buttons": + this.optionbuttonBorderRadius = value; + break; } } @@ -534,9 +569,6 @@ const enableMenu = args.ENABLE_MENU; const action = args.ACTION; switch (enableMenu) { - case 'Input Box': - this.isInputEnabled = action === 'Enabled'; - break; case 'Button 2': this.showCancelButton = action === 'Enabled'; break; @@ -548,6 +580,10 @@ break; } } + + setInputType(args) { + this.isInputEnabled = args.ACTION; + } setButtonText(args) { const buttonMenu = args.BUTTON_MENU; @@ -565,6 +601,9 @@ case 'Button 4': this.Button4Text = text; break; + case 'Dropdown': + this.DropdownText = text; + break; } } @@ -768,7 +807,7 @@ submitButton.textContent = this.submitButtonText; submitButton.addEventListener('click', () => { - if (this.isInputEnabled) { + if (this.isInputEnabled !== 'Disabled') { this.userInput = inputField.value; } else { this.userInput = this.submitButtonText; @@ -796,7 +835,7 @@ cancelButton.style.display = this.showCancelButton ? 'inline-block' : 'none'; cancelButton.addEventListener('click', () => { - if (!this.isInputEnabled) { + if (this.isInputEnabled === 'Disabled') { this.userInput = this.cancelButtonText; } this.isWaitingForInput = false; @@ -822,7 +861,9 @@ Button3.style.display = this.showButton3 ? 'inline-block' : 'none'; Button3.addEventListener('click', () => { - this.userInput = this.Button3Text; + if (this.isInputEnabled === 'Disabled') { + this.userInput = this.Button3Text; + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -846,7 +887,9 @@ Button4.style.display = this.showButton4 ? 'inline-block' : 'none'; Button4.addEventListener('click', () => { - this.userInput = this.Button4Text; + if (this.isInputEnabled === 'Disabled') { + this.userInput = this.Button4Text; + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -856,11 +899,66 @@ resolve(); this.askBoxCount--; }); + + const dropdown = document.createElement('div'); + dropdown.className = 'dropdown'; + + const dropdownButton = document.createElement('button'); + dropdownButton.className = 'dropdown-button'; + dropdownButton.textContent = this.DropdownText; + dropdownButton.style.padding = '5px 10px'; + dropdownButton.style.backgroundColor = this.optionbuttonColor; + dropdownButton.style.color = this.optionButtonTextColor; + dropdownButton.style.border = 'none'; + dropdownButton.style.borderRadius = this.optionbuttonBorderRadius + 'px'; + + const dropdownContent = document.createElement('div'); + dropdownContent.className = 'dropdown-content'; + + let isDropdownOpen = false; + + const optionList = this.optionList; + const numOfOptions = optionList.split(',').length; + const options = this.optionList.split(','); + for (let i = 1; i <= numOfOptions; i++) { + const optionButton = document.createElement('button'); + optionButton.style.marginRight = '5px'; + optionButton.style.marginTop = '10px'; + optionButton.style.padding = '5px 10px'; + optionButton.style.backgroundColor = this.optionbuttonColor; + optionButton.style.color = this.optionButtonTextColor; + optionButton.style.border = 'none'; + optionButton.style.borderRadius = this.optionbuttonBorderRadius + 'px'; + optionButton.textContent = `${options[i - 1]}`; + optionButton.addEventListener('click', () => { + inputField.value = `${options[i - 1]}`; + }); + dropdownContent.appendChild(optionButton); + } + + dropdownButton.addEventListener('mouseover', () => { + if (!isDropdownOpen) { + overlay.insertBefore(dropdownContent, submitButton); + isDropdownOpen = true; + } + }); + + overlay.addEventListener('mouseleave', () => { + if (isDropdownOpen) { + overlay.removeChild(dropdownContent); + isDropdownOpen = false; + } + }); overlay.appendChild(questionText); - if (this.isInputEnabled) { - overlay.appendChild(inputField); + if (this.isInputEnabled !== 'Disabled') { + if (this.isInputEnabled === 'Enabled') { + overlay.appendChild(inputField); + } else { + dropdown.appendChild(dropdownButton); + overlay.appendChild(dropdown); + } } overlay.appendChild(submitButton); @@ -934,7 +1032,11 @@ } setSubmitEvent(args) { - this.forceInput = args.ENTER; + this.forceInput = args.ENTER; + } + + setDropdown(args) { + this.optionList = args.DROPDOWN } setImage(args) { From 6cd51dc627e1143ce670da32da6823cdb8c229a1 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 6 Aug 2023 09:36:02 -0700 Subject: [PATCH 06/46] Update Better Input Bug fixes and Quality of life stuff --- extensions/SharkPool/Better Input | 224 ++++++++++++++++++++++-------- 1 file changed, 165 insertions(+), 59 deletions(-) diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input index b611e164e4..0e712b2c6d 100644 --- a/extensions/SharkPool/Better Input +++ b/extensions/SharkPool/Better Input @@ -1,6 +1,7 @@ /* * This extension was made by SharkPool -* Version 1.8 (Bug fixes and Dropdown-able Menus) +* Version 1.9 (Visual bug fixes and Remodeled Effects) +* Next Update: Add Sliders and other Suggested Features * Do NOT delete these comments */ @@ -24,7 +25,7 @@ class BetterInputSP { constructor() { this.isWaitingForInput = false; - this.userInput = null; + this.userInput = ''; this.fontSize = '14px'; this.questionColor = '#000000'; this.inputColor = '#000000'; @@ -34,8 +35,8 @@ this.textAlign = 'left'; this.fontFamily = 'Arial'; this.showCancelButton = true; - this.showButton3 = true; - this.showButton4 = true; + this.showButton3 = false; + this.showButton4 = false; this.submitButtonText = 'Submit'; this.cancelButtonText = 'Cancel'; this.Button3Text = 'Okay'; @@ -67,6 +68,9 @@ this.overlayInput = null; this.overlayImage = null; this.optionList = 'Option 1,Option 2,Option 3'; + this.splitKey = ','; + this.enterSpeed = '10'; + this.exitSpeed = '10'; } getInfo() { @@ -132,12 +136,16 @@ { opcode: 'setDropdown', blockType: Scratch.BlockType.COMMAND, - text: 'set dropdown options to array: [DROPDOWN]', + text: 'set dropdown options to list: [DROPDOWN] split by [SPLITTER]', arguments: { DROPDOWN: { type: Scratch.ArgumentType.STRING, defaultValue: 'option 1,option 2,option 3', }, + SPLITTER: { + type: Scratch.ArgumentType.STRING, + defaultValue: ',', + }, }, }, { @@ -217,6 +225,22 @@ blockType: Scratch.BlockType.LABEL, text: 'Positioning', }, + { + opcode: "setPrePosition", + blockType: Scratch.BlockType.COMMAND, + text: "preset textbox position to x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, { opcode: "setPosition", blockType: Scratch.BlockType.COMMAND, @@ -328,6 +352,18 @@ }, }, }, + { + opcode: 'setEnterSpeed', + blockType: Scratch.BlockType.COMMAND, + text: 'set enter effect speed to [SPEED]', + blockIconURI: effectIcon, + arguments: { + SPEED: { + type: Scratch.ArgumentType.STRING, + defaultValue: '10', + }, + }, + }, { opcode: 'setExitEffect', blockType: Scratch.BlockType.COMMAND, @@ -341,6 +377,18 @@ }, }, }, + { + opcode: 'setExitSpeed', + blockType: Scratch.BlockType.COMMAND, + text: 'set exit effect speed to [SPEED]', + blockIconURI: effectIcon, + arguments: { + SPEED: { + type: Scratch.ArgumentType.STRING, + defaultValue: '10', + }, + }, + }, { blockType: Scratch.BlockType.LABEL, text: 'Operations', @@ -385,8 +433,8 @@ enterMenu: ['Disabled', 'Enter Key', 'Shift + Enter key'], buttonActionMenu: ['Enabled', 'Disabled'], inputActionMenu: ['Enabled', 'Disabled', 'Dropdown'], - enterEffectMenu: ['None', 'Fade in', 'Grow'], - exitEffectMenu: ['None', 'Fade out', 'Shrink'], + enterEffectMenu: ['None', 'Fade in', 'Grow', 'Both'], + exitEffectMenu: ['None', 'Fade out', 'Shrink', 'Both'], buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4', 'Dropdown'], enableMenu: ['Button 2', 'Button 3', 'Button 4'], elementMenu: ['Textbox', 'Input Box', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons'], @@ -444,7 +492,7 @@ this.button4TextColor = colorValue; break; case 'Dropdown Text': - this.optionButtonTextColor = colorValue; + this.optionbuttonTextColor = colorValue; break; } } @@ -494,6 +542,9 @@ case 'Grow': this.enterEffect = 'growIn'; break; + case 'Both': + this.enterEffect = 'Both'; + break; default: this.enterEffect = null; break; @@ -512,16 +563,23 @@ case 'Shrink': this.exitEffect = 'shrinkOut'; break; + case 'Both': + this.exitEffect = 'Both'; + break; default: this.exitEffect = null; break; } } - + + setPrePosition(args) { + this.textBoxX = args.X; + this.textBoxY = args.Y * -1; + } + setPosition(args) { this.textBoxX = args.X; this.textBoxY = args.Y * -1; - const overlays = document.querySelectorAll(".ask-box"); overlays.forEach((overlay) => { @@ -628,36 +686,53 @@ this.askBoxPromise = null; } this.askBoxCount = 0; - this.userInput = 'removed'; + this.userInput = ''; } applyEnterEffect(overlay) { - if (this.enterEffect === 'fadeIn') { - overlay.style.opacity = '0'; - overlay.style.transform = 'scale(1)'; - - let currentOpacity = 0; + overlay.style.opacity = '1'; + overlay.style.transform = 'scale(1)'; + let currentOpacity = 0; + let currentScale = 0; + + if (this.enterEffect !== 'None') { + if (this.enterEffect === 'fadeIn' || this.enterEffect === 'Both') { + overlay.style.opacity = '0'; + } + if (this.enterEffect === 'growIn' || this.enterEffect === 'Both') { + overlay.style.transform = 'scale(0)'; + overlay.style.transition = 'opacity 0.3s'; + } + const step = () => { - currentOpacity += 10; - overlay.style.opacity = `${currentOpacity}%`; - if (currentOpacity < 100) { - requestAnimationFrame(step); + if ((this.enterEffect === 'fadeIn' || this.enterEffect === 'Both') && currentOpacity < 100) { + currentOpacity += this.enterSpeed; + overlay.style.opacity = `${currentOpacity}%`; } - }; - requestAnimationFrame(step); - } else if (this.enterEffect === 'growIn') { - overlay.style.opacity = '1'; - overlay.style.transform = 'scale(0)'; - overlay.style.transition = 'opacity 0.3s'; - - let currentScale = 0; - const step = () => { - currentScale += 10; - overlay.style.transform = `scale(${currentScale / 100})`; - if (currentScale < 100) { - requestAnimationFrame(step); + + if ((this.enterEffect === 'growIn' || this.enterEffect === 'Both') && currentScale < 100) { + currentScale += this.enterSpeed; + overlay.style.transform = `scale(${currentScale / 100})`; + } + if (this.enterEffect === 'Both') { + if (currentOpacity < 100 || currentScale < 100) { + requestAnimationFrame(step); + } + } else if (this.enterEffect === 'growIn'){ + if (currentScale < 100) { + requestAnimationFrame(step); + } + } else { + if (currentOpacity < 100) { + requestAnimationFrame(step); + } } }; + + if (this.enterEffect === 'growIn' || this.enterEffect === 'Both') { + overlay.style.transition = 'opacity 0.3s'; + } + requestAnimationFrame(step); } else { overlay.style.opacity = '1'; @@ -665,33 +740,34 @@ } applyExitEffect(overlay) { - if (this.exitEffect === 'fadeOut') { - overlay.style.transition = 'opacity 0.5s'; + let currentScale = 100; + let currentOpacity = 0; + + if (this.exitEffect !== 'None') { + if (this.exitEffect === 'fadeOut') { + overlay.style.transition = 'opacity 0.5s'; + } else { + overlay.style.transition = 'transform 0.5s, opacity 0.5s'; + } - let currentOpacity = 0; const step = () => { - currentOpacity -= 5; - overlay.style.opacity = `${currentOpacity}%`; - if (currentOpacity > -100) { - requestAnimationFrame(step); - } else { - document.body.removeChild(overlay); + if ((this.exitEffect === 'fadeOut' || this.exitEffect === 'Both') && currentOpacity < 100) { + currentOpacity -= this.exitSpeed; + overlay.style.opacity = `${currentOpacity}%`; } - }; - requestAnimationFrame(step); - } else if (this.exitEffect === 'shrinkOut') { - overlay.style.transition = 'transform 0.3s, opacity 0.3s'; - let currentScale = 100; - const step = () => { - currentScale -= 15; - overlay.style.transform = `scale(${currentScale / 100})`; - if (currentScale > -200) { + if ((this.exitEffect === 'shrinkOut' || this.exitEffect === 'Both') && currentScale > 0) { + currentScale -= this.exitSpeed; + overlay.style.transform = `scale(${currentScale / 100})`; + } + + if ((this.exitEffect === 'Both' && (currentOpacity > -200 || currentScale > -100)) || (this.exitEffect === 'shrinkOut' && currentScale > -100) || (this.exitEffect !== 'Both' && currentOpacity > -200)) { requestAnimationFrame(step); } else { document.body.removeChild(overlay); } }; + requestAnimationFrame(step); } else { document.body.removeChild(overlay); @@ -837,7 +913,9 @@ cancelButton.addEventListener('click', () => { if (this.isInputEnabled === 'Disabled') { this.userInput = this.cancelButtonText; - } + } else { + this.userInput = '' + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -863,7 +941,9 @@ Button3.addEventListener('click', () => { if (this.isInputEnabled === 'Disabled') { this.userInput = this.Button3Text; - } + } else { + this.userInput = '' + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -889,7 +969,9 @@ Button4.addEventListener('click', () => { if (this.isInputEnabled === 'Disabled') { this.userInput = this.Button4Text; - } + } else { + this.userInput = '' + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -908,7 +990,7 @@ dropdownButton.textContent = this.DropdownText; dropdownButton.style.padding = '5px 10px'; dropdownButton.style.backgroundColor = this.optionbuttonColor; - dropdownButton.style.color = this.optionButtonTextColor; + dropdownButton.style.color = this.optionbuttonTextColor; dropdownButton.style.border = 'none'; dropdownButton.style.borderRadius = this.optionbuttonBorderRadius + 'px'; @@ -918,20 +1000,29 @@ let isDropdownOpen = false; const optionList = this.optionList; - const numOfOptions = optionList.split(',').length; - const options = this.optionList.split(','); + const numOfOptions = optionList.split(this.splitKey).length; + const options = this.optionList.split(this.splitKey); for (let i = 1; i <= numOfOptions; i++) { - const optionButton = document.createElement('button'); + const optionButton = document.createElement('button'); optionButton.style.marginRight = '5px'; optionButton.style.marginTop = '10px'; optionButton.style.padding = '5px 10px'; optionButton.style.backgroundColor = this.optionbuttonColor; - optionButton.style.color = this.optionButtonTextColor; + optionButton.style.color = this.optionbuttonTextColor; optionButton.style.border = 'none'; optionButton.style.borderRadius = this.optionbuttonBorderRadius + 'px'; optionButton.textContent = `${options[i - 1]}`; + optionButton.style.filter = 'brightness(1)'; + optionButton.addEventListener('click', () => { inputField.value = `${options[i - 1]}`; + + for (let j = 0; j < numOfOptions; j++) { + const otherButton = dropdownContent.children[j]; + otherButton.style.filter = 'brightness(1)'; + } + + optionButton.style.filter = 'brightness(1.5)'; }); dropdownContent.appendChild(optionButton); } @@ -1037,6 +1128,21 @@ setDropdown(args) { this.optionList = args.DROPDOWN + this.splitKey = args.SPLITTER + } + + setEnterSpeed(args) { + this.enterSpeed = Math.abs(args.SPEED) + if (this.enterSpeed < 1) { + this.enterSpeed = 1 + } + } + + setExitSpeed(args) { + this.exitSpeed = Math.abs(args.SPEED) + if (this.exitSpeed < 1) { + this.exitSpeed = 1 + } } setImage(args) { From 77fc0c943c9da2e685206cd9688b4045aeecc524 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:40:47 -0700 Subject: [PATCH 07/46] Update Better Input --- extensions/SharkPool/Better Input | 130 +++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 38 deletions(-) diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input index 0e712b2c6d..6704d6b11b 100644 --- a/extensions/SharkPool/Better Input +++ b/extensions/SharkPool/Better Input @@ -1,7 +1,7 @@ /* * This extension was made by SharkPool -* Version 1.9 (Visual bug fixes and Remodeled Effects) -* Next Update: Add Sliders and other Suggested Features +* Version 2.0 (Sliders, Bug Fixes, Better Force Input, and more Fonts) +* Next Update: None right now * Do NOT delete these comments */ @@ -69,8 +69,11 @@ this.overlayImage = null; this.optionList = 'Option 1,Option 2,Option 3'; this.splitKey = ','; - this.enterSpeed = '10'; - this.exitSpeed = '10'; + this.minSlider = '0'; + this.maxSlider = '100'; + this.defaultSlider = '50'; + this.enterSpeed = 10; + this.exitSpeed = 10; } getInfo() { @@ -148,6 +151,25 @@ }, }, }, + { + opcode: 'setSlider', + blockType: Scratch.BlockType.COMMAND, + text: 'set slider to min: [MIN] max: [MAX] default: [DEFAULT]', + arguments: { + MIN: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: '0', + }, + MAX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: '100', + }, + DEFAULT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: '50', + }, + }, + }, { blockType: Scratch.BlockType.LABEL, text: 'Formatting', @@ -429,17 +451,20 @@ ], menus: { alignmentMenu: ['left', 'right', 'center'], - fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive', 'Lucida Console', 'Scratch','Arial Black', 'Calibri', 'Consolas', 'Handwriting', 'Marker','Curly', 'Pixel'], - enterMenu: ['Disabled', 'Enter Key', 'Shift + Enter key'], + fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive', 'Lucida Console', 'Scratch','Arial Black', 'Calibri', 'Consolas', 'Handwriting', 'Marker','Curly', 'Pixel', 'MS PGothic', 'Malgun Gothic', 'Microsoft YaHei'], buttonActionMenu: ['Enabled', 'Disabled'], - inputActionMenu: ['Enabled', 'Disabled', 'Dropdown'], + inputActionMenu: ['Enabled', 'Disabled', 'Dropdown', 'Slider'], enterEffectMenu: ['None', 'Fade in', 'Grow', 'Both'], exitEffectMenu: ['None', 'Fade out', 'Shrink', 'Both'], buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4', 'Dropdown'], enableMenu: ['Button 2', 'Button 3', 'Button 4'], elementMenu: ['Textbox', 'Input Box', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons'], colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons', 'Button 1 Text', 'Button 2 Text', 'Button 3 Text', 'Button 4 Text', 'Dropdown Text'], - }, + enterMenu: { + acceptReporters: true, + items: ['Disabled', 'Enter Key', 'Shift + Enter Key'], + } + } }; } @@ -479,6 +504,9 @@ case 'Dropdown Buttons': this.optionbuttonColor = colorValue; break; + case 'Slider': + this.sliderColor = colorValue; + break; case 'Button 1 Text': this.submitButtonTextColor = colorValue; break; @@ -527,6 +555,9 @@ case "Dropdown Buttons": this.optionbuttonBorderRadius = value; break; + case "Slider": + this.sliderBorderRadius = value; + break; } } @@ -545,9 +576,6 @@ case 'Both': this.enterEffect = 'Both'; break; - default: - this.enterEffect = null; - break; } } @@ -566,9 +594,6 @@ case 'Both': this.exitEffect = 'Both'; break; - default: - this.exitEffect = null; - break; } } @@ -622,6 +647,12 @@ setFontFamily(args) { this.fontFamily = args.FONT; } + + setSlider(args) { + this.minSlider = args.MIN; + this.maxSlider = args.MAX; + this.defaultSlider = args.DEFAULT; + } setEnable(args) { const enableMenu = args.ENABLE_MENU; @@ -692,6 +723,7 @@ applyEnterEffect(overlay) { overlay.style.opacity = '1'; overlay.style.transform = 'scale(1)'; + let currentOpacity = 0; let currentScale = 0; @@ -699,6 +731,7 @@ if (this.enterEffect === 'fadeIn' || this.enterEffect === 'Both') { overlay.style.opacity = '0'; } + if (this.enterEffect === 'growIn' || this.enterEffect === 'Both') { overlay.style.transform = 'scale(0)'; overlay.style.transition = 'opacity 0.3s'; @@ -714,18 +747,11 @@ currentScale += this.enterSpeed; overlay.style.transform = `scale(${currentScale / 100})`; } - if (this.enterEffect === 'Both') { - if (currentOpacity < 100 || currentScale < 100) { - requestAnimationFrame(step); - } - } else if (this.enterEffect === 'growIn'){ - if (currentScale < 100) { - requestAnimationFrame(step); - } - } else { - if (currentOpacity < 100) { - requestAnimationFrame(step); - } + + if ((this.enterEffect === 'Both' && (currentOpacity < 100 || currentScale < 100)) || + (this.enterEffect === 'growIn' && currentScale < 100) || + (this.enterEffect !== 'Both' && currentOpacity < 100)) { + requestAnimationFrame(step); } }; @@ -816,14 +842,15 @@ if (this.forceInput === 'Enter Key') { overlayInput = 'Enter'; + } else if (this.forceInput === 'Shift + Enter Key') { + overlayInput = 'ShiftEnter'; } else { - overlayInput = 'ShiftEnter'; + overlayInput = this.forceInput; } const handleKeydown = (event) => { if ( - (overlayInput === 'Enter' && event.key === 'Enter') || - (overlayInput === 'ShiftEnter' && event.shiftKey && event.key === 'Enter') + (overlayInput === 'ShiftEnter' && event.shiftKey && event.key === 'Enter') || (event.key === overlayInput) ) { this.userInput = inputField.value; this.isWaitingForInput = false; @@ -914,8 +941,8 @@ if (this.isInputEnabled === 'Disabled') { this.userInput = this.cancelButtonText; } else { - this.userInput = '' - } + this.userInput = '' + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -942,8 +969,8 @@ if (this.isInputEnabled === 'Disabled') { this.userInput = this.Button3Text; } else { - this.userInput = '' - } + this.userInput = '' + } this.isWaitingForInput = false; if (this.exitEffect) { this.applyExitEffect(overlay); @@ -1003,7 +1030,7 @@ const numOfOptions = optionList.split(this.splitKey).length; const options = this.optionList.split(this.splitKey); for (let i = 1; i <= numOfOptions; i++) { - const optionButton = document.createElement('button'); + const optionButton = document.createElement('button'); optionButton.style.marginRight = '5px'; optionButton.style.marginTop = '10px'; optionButton.style.padding = '5px 10px'; @@ -1041,22 +1068,49 @@ } }); + const sliderContainer = document.createElement('div'); + sliderContainer.classList.add('slider-container'); + + const slider = document.createElement('input'); + slider.type = 'range'; + slider.min = this.minSlider; + slider.max = this.maxSlider; + slider.value = this.defaultSlider; + + sliderContainer.appendChild(slider); + + const valueDisplay = document.createElement('span'); + valueDisplay.classList.add('slider-value'); + sliderContainer.appendChild(valueDisplay); + valueDisplay.style.color = this.questionColor; + valueDisplay.textContent = slider.value; + + slider.addEventListener('input', () => { + valueDisplay.textContent = slider.value; + inputField.value = valueDisplay.textContent; + }); + overlay.appendChild(questionText); - + if (this.isInputEnabled !== 'Disabled') { if (this.isInputEnabled === 'Enabled') { overlay.appendChild(inputField); - } else { + } else if (this.isInputEnabled === 'Dropdown'){ dropdown.appendChild(dropdownButton); overlay.appendChild(dropdown); + } else { + overlay.appendChild(sliderContainer); + overlay.appendChild(valueDisplay); + overlay.appendChild(document.createElement('br')); } } - + overlay.appendChild(submitButton); overlay.appendChild(cancelButton); overlay.appendChild(Button3); overlay.appendChild(Button4); - overlay.appendChild(overlayImageContainer); + overlay.appendChild(overlayImageContainer); + document.body.appendChild(overlay); inputField.focus(); From 3458ae5ba4ef6521b2a0601574ff66f3ee8941f5 Mon Sep 17 00:00:00 2001 From: Muffin Date: Tue, 15 Aug 2023 22:03:04 -0500 Subject: [PATCH 08/46] move it to the right spot and run prettier --- extensions/SharkPool/Better Input | 1208 ------------------------- extensions/SharkPool/BetterInput.js | 1305 +++++++++++++++++++++++++++ 2 files changed, 1305 insertions(+), 1208 deletions(-) delete mode 100644 extensions/SharkPool/Better Input create mode 100644 extensions/SharkPool/BetterInput.js diff --git a/extensions/SharkPool/Better Input b/extensions/SharkPool/Better Input deleted file mode 100644 index 6704d6b11b..0000000000 --- a/extensions/SharkPool/Better Input +++ /dev/null @@ -1,1208 +0,0 @@ -/* -* This extension was made by SharkPool -* Version 2.0 (Sliders, Bug Fixes, Better Force Input, and more Fonts) -* Next Update: None right now -* Do NOT delete these comments -*/ - -(function(Scratch) { - 'use strict'; - - if (!Scratch.extensions.unsandboxed) { - throw new Error('Better Input must run unsandboxed'); - } - - const menuIconURI = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=='; - - const blockIconURI = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; - - const formatIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; - - const colorIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=='; - - const effectIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+'; - - class BetterInputSP { - constructor() { - this.isWaitingForInput = false; - this.userInput = ''; - this.fontSize = '14px'; - this.questionColor = '#000000'; - this.inputColor = '#000000'; - this.textBoxColor = '#ffffff'; - this.inputBackgroundColor = '#ffffff'; - this.inputOutlineColor = '#000000'; - this.textAlign = 'left'; - this.fontFamily = 'Arial'; - this.showCancelButton = true; - this.showButton3 = false; - this.showButton4 = false; - this.submitButtonText = 'Submit'; - this.cancelButtonText = 'Cancel'; - this.Button3Text = 'Okay'; - this.Button4Text = 'No'; - this.DropdownText = 'Dropdown'; - this.submitButtonColor = '#0074D9'; - this.cancelButtonColor = '#d9534f'; - this.button3Color = '#0074D9'; - this.button4Color = '#d9534f'; - this.optionbuttonColor = '#5f5f5f'; - this.cancelButtonBorderRadius = 5; - this.submitButtonBorderRadius = 5; - this.button3BorderRadius = 5; - this.button4BorderRadius = 5; - this.optionbuttonBorderRadius = 5; - this.submitButtonTextColor = '#ffffff'; - this.cancelButtonTextColor = '#ffffff'; - this.button3TextColor = '#ffffff'; - this.button4TextColor = '#ffffff'; - this.optionbuttonTextColor = '#ffffff'; - this.textBoxBorderRadius = 5; - this.inputBoxRadius = 4; - this.isInputEnabled = 'Enabled'; - this.textBoxX = 0; - this.textBoxY = 0; - this.askBoxCount = 0; - this.maxBoxCount = 1; - this.forceInput = 'Disabled'; - this.overlayInput = null; - this.overlayImage = null; - this.optionList = 'Option 1,Option 2,Option 3'; - this.splitKey = ','; - this.minSlider = '0'; - this.maxSlider = '100'; - this.defaultSlider = '50'; - this.enterSpeed = 10; - this.exitSpeed = 10; - } - - getInfo() { - return { - id: 'BetterInputSP', - name: 'Better Input', - color1: '#9400ff', - menuIconURI, - blockIconURI, - blocks: [ - { - blockType: Scratch.BlockType.LABEL, - text: 'Text Blocks', - }, - { - opcode: 'askAndWait', - blockType: Scratch.BlockType.COMMAND, - text: 'ask [question] and wait', - arguments: { - question: { - type: Scratch.ArgumentType.STRING, - defaultValue: 'What is your name?', - }, - }, - }, - { - opcode: 'askAndWaitForInput', - blockType: Scratch.BlockType.REPORTER, - text: 'ask [question] and wait', - arguments: { - question: { - type: Scratch.ArgumentType.STRING, - defaultValue: 'What is your name?', - }, - }, - }, - { - opcode: 'getUserInput', - blockType: Scratch.BlockType.REPORTER, - text: 'user input', - }, - { - opcode: "removeAskBoxes", - blockType: Scratch.BlockType.COMMAND, - text: "remove all ask boxes", - }, - { - opcode: 'setButtonText', - blockType: Scratch.BlockType.COMMAND, - text: 'set [BUTTON_MENU] text to [TEXT]', - arguments: { - BUTTON_MENU: { - type: Scratch.ArgumentType.STRING, - menu: 'buttonMenu', - defaultValue: 'Button 1', - }, - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: 'Submit', - }, - }, - }, - { - opcode: 'setDropdown', - blockType: Scratch.BlockType.COMMAND, - text: 'set dropdown options to list: [DROPDOWN] split by [SPLITTER]', - arguments: { - DROPDOWN: { - type: Scratch.ArgumentType.STRING, - defaultValue: 'option 1,option 2,option 3', - }, - SPLITTER: { - type: Scratch.ArgumentType.STRING, - defaultValue: ',', - }, - }, - }, - { - opcode: 'setSlider', - blockType: Scratch.BlockType.COMMAND, - text: 'set slider to min: [MIN] max: [MAX] default: [DEFAULT]', - arguments: { - MIN: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: '0', - }, - MAX: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: '100', - }, - DEFAULT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: '50', - }, - }, - }, - { - blockType: Scratch.BlockType.LABEL, - text: 'Formatting', - }, - { - opcode: 'setTextAlignment', - blockType: Scratch.BlockType.COMMAND, - text: 'set alignment to [ALIGNMENT]', - blockIconURI: formatIcon, - arguments: { - ALIGNMENT: { - type: Scratch.ArgumentType.STRING, - menu: 'alignmentMenu', - defaultValue: 'left', - }, - }, - }, - { - opcode: 'setFontFamily', - blockType: Scratch.BlockType.COMMAND, - text: 'set font to [FONT]', - blockIconURI: formatIcon, - arguments: { - FONT: { - type: Scratch.ArgumentType.STRING, - menu: 'fontMenu', - defaultValue: 'Arial', - }, - }, - }, - { - opcode: 'setInputType', - blockType: Scratch.BlockType.COMMAND, - text: 'set Input Box to be [ACTION]', - blockIconURI: formatIcon, - arguments: { - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: 'inputActionMenu', - defaultValue: 'Enabled', - }, - }, - }, - { - opcode: 'setEnable', - blockType: Scratch.BlockType.COMMAND, - text: 'set [ENABLE_MENU] to be [ACTION]', - blockIconURI: formatIcon, - arguments: { - ENABLE_MENU: { - type: Scratch.ArgumentType.STRING, - menu: 'enableMenu', - defaultValue: 'Button 2', - }, - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: 'buttonActionMenu', - defaultValue: 'Enabled', - }, - }, - }, - { - opcode: 'setFontSize', - blockType: Scratch.BlockType.COMMAND, - text: 'set font size to [SIZE]', - blockIconURI: formatIcon, - arguments: { - SIZE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 14, - }, - }, - }, - { - blockType: Scratch.BlockType.LABEL, - text: 'Positioning', - }, - { - opcode: "setPrePosition", - blockType: Scratch.BlockType.COMMAND, - text: "preset textbox position to x: [X] y: [Y]", - blockIconURI: formatIcon, - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - }, - }, - { - opcode: "setPosition", - blockType: Scratch.BlockType.COMMAND, - text: "set textbox position to x: [X] y: [Y]", - blockIconURI: formatIcon, - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - }, - }, - { - opcode: "changePosition", - blockType: Scratch.BlockType.COMMAND, - text: "change textbox position by x: [X] y: [Y]", - blockIconURI: formatIcon, - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - }, - }, - { - opcode: 'getXpos', - blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, - text: 'x position', - }, - { - opcode: 'getYpos', - blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, - text: 'y position', - }, - { - blockType: Scratch.BlockType.LABEL, - text: 'Visual Settings', - }, - { - opcode: 'setColorSettings', - blockType: Scratch.BlockType.COMMAND, - text: 'set [COLOR_TYPE] color to [COLOR]', - blockIconURI: colorIcon, - arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: 'colorSettingsMenu', - defaultValue: 'Question', - }, - COLOR: { - type: Scratch.ArgumentType.COLOR, - defaultValue: '#000000', - }, - }, - }, - { - opcode: "setBorderRadius", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] border radius to [VALUE]", - blockIconURI: colorIcon, - arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - defaultValue: "Textbox", - }, - VALUE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, - }, - }, - }, - { - opcode: "setImage", - blockType: Scratch.BlockType.COMMAND, - text: "set background image to [IMAGE]", - blockIconURI: colorIcon, - arguments: { - IMAGE: { - type: Scratch.ArgumentType.STRING, - defaultValue: 'input-url-or-uri-here', - }, - }, - }, - { - blockType: Scratch.BlockType.LABEL, - text: 'Effects', - }, - { - opcode: 'setEnterEffect', - blockType: Scratch.BlockType.COMMAND, - text: 'set enter effect to [ENTER_EFFECT]', - blockIconURI: effectIcon, - arguments: { - ENTER_EFFECT: { - type: Scratch.ArgumentType.STRING, - menu: 'enterEffectMenu', - defaultValue: 'None', - }, - }, - }, - { - opcode: 'setEnterSpeed', - blockType: Scratch.BlockType.COMMAND, - text: 'set enter effect speed to [SPEED]', - blockIconURI: effectIcon, - arguments: { - SPEED: { - type: Scratch.ArgumentType.STRING, - defaultValue: '10', - }, - }, - }, - { - opcode: 'setExitEffect', - blockType: Scratch.BlockType.COMMAND, - text: 'set exit effect to [EXIT_EFFECT]', - blockIconURI: effectIcon, - arguments: { - EXIT_EFFECT: { - type: Scratch.ArgumentType.STRING, - menu: 'exitEffectMenu', - defaultValue: 'None', - }, - }, - }, - { - opcode: 'setExitSpeed', - blockType: Scratch.BlockType.COMMAND, - text: 'set exit effect speed to [SPEED]', - blockIconURI: effectIcon, - arguments: { - SPEED: { - type: Scratch.ArgumentType.STRING, - defaultValue: '10', - }, - }, - }, - { - blockType: Scratch.BlockType.LABEL, - text: 'Operations', - }, - { - opcode: 'setSubmitEvent', - blockType: Scratch.BlockType.COMMAND, - text: 'set force input to [ENTER]', - arguments: { - ENTER: { - type: Scratch.ArgumentType.STRING, - menu: 'enterMenu', - defaultValue: 'Disabled', - }, - }, - }, - { - opcode: 'setMaxBoxCount', - blockType: Scratch.BlockType.COMMAND, - text: 'set max box count to: [MAX]', - arguments: { - MAX: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1, - }, - }, - }, - { - opcode: 'getBoxCount', - blockType: Scratch.BlockType.REPORTER, - text: 'box count', - }, - { - opcode: 'getMaxCount', - blockType: Scratch.BlockType.REPORTER, - text: 'box limit', - }, - ], - menus: { - alignmentMenu: ['left', 'right', 'center'], - fontMenu: ['Arial', 'Times New Roman', 'Comic Sans MS', 'Verdana', 'Courier New', 'Impact', 'Cursive', 'Lucida Console', 'Scratch','Arial Black', 'Calibri', 'Consolas', 'Handwriting', 'Marker','Curly', 'Pixel', 'MS PGothic', 'Malgun Gothic', 'Microsoft YaHei'], - buttonActionMenu: ['Enabled', 'Disabled'], - inputActionMenu: ['Enabled', 'Disabled', 'Dropdown', 'Slider'], - enterEffectMenu: ['None', 'Fade in', 'Grow', 'Both'], - exitEffectMenu: ['None', 'Fade out', 'Shrink', 'Both'], - buttonMenu: ['Button 1','Button 2', 'Button 3', 'Button 4', 'Dropdown'], - enableMenu: ['Button 2', 'Button 3', 'Button 4'], - elementMenu: ['Textbox', 'Input Box', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons'], - colorSettingsMenu: ['Question', 'Input Text', 'Textbox', 'Input Background', 'Input Outline', 'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Dropdown Buttons', 'Button 1 Text', 'Button 2 Text', 'Button 3 Text', 'Button 4 Text', 'Dropdown Text'], - enterMenu: { - acceptReporters: true, - items: ['Disabled', 'Enter Key', 'Shift + Enter Key'], - } - } - }; - } - - setColorSettings(args) { - const colorType = args.COLOR_TYPE; - const colorValue = args.COLOR; - - switch (colorType) { - case 'Question': - this.questionColor = colorValue; - break; - case 'Input Text': - this.inputColor = colorValue; - break; - case 'Textbox': - this.textBoxColor = colorValue; - this.overlayImage = null; - break; - case 'Input Background': - this.inputBackgroundColor = colorValue; - break; - case 'Input Outline': - this.inputOutlineColor = colorValue; - break; - case 'Button 1': - this.submitButtonColor = colorValue; - break; - case 'Button 2': - this.cancelButtonColor = colorValue; - break; - case 'Button 3': - this.button3Color = colorValue; - break; - case 'Button 4': - this.button4Color = colorValue; - break; - case 'Dropdown Buttons': - this.optionbuttonColor = colorValue; - break; - case 'Slider': - this.sliderColor = colorValue; - break; - case 'Button 1 Text': - this.submitButtonTextColor = colorValue; - break; - case 'Button 2 Text': - this.cancelButtonTextColor = colorValue; - break; - case 'Button 3 Text': - this.button3TextColor = colorValue; - break; - case 'Button 4 Text': - this.button4TextColor = colorValue; - break; - case 'Dropdown Text': - this.optionbuttonTextColor = colorValue; - break; - } - } - - setBorderRadius(args) { - const element = args.ELEMENT; - let value = args.VALUE; - - if (value < 0) { - value = 0; - } - - switch (element) { - case "Textbox": - this.textBoxBorderRadius = value; - break; - case "Button 1": - this.cancelButtonBorderRadius = value; - break; - case "Button 2": - this.submitButtonBorderRadius = value; - break; - case "Button 3": - this.button3BorderRadius = value; - break; - case "Button 4": - this.button4BorderRadius = value; - break; - case "Input Box": - this.inputBoxRadius = value; - break; - case "Dropdown Buttons": - this.optionbuttonBorderRadius = value; - break; - case "Slider": - this.sliderBorderRadius = value; - break; - } - } - - setEnterEffect(args) { - const enterEffect = args.ENTER_EFFECT; - switch (enterEffect) { - case 'None': - this.enterEffect = null; - break; - case 'Fade in': - this.enterEffect = 'fadeIn'; - break; - case 'Grow': - this.enterEffect = 'growIn'; - break; - case 'Both': - this.enterEffect = 'Both'; - break; - } - } - - setExitEffect(args) { - const exitEffect = args.EXIT_EFFECT; - switch (exitEffect) { - case 'None': - this.exitEffect = null; - break; - case 'Fade out': - this.exitEffect = 'fadeOut'; - break; - case 'Shrink': - this.exitEffect = 'shrinkOut'; - break; - case 'Both': - this.exitEffect = 'Both'; - break; - } - } - - setPrePosition(args) { - this.textBoxX = args.X; - this.textBoxY = args.Y * -1; - } - - setPosition(args) { - this.textBoxX = args.X; - this.textBoxY = args.Y * -1; - - const overlays = document.querySelectorAll(".ask-box"); - overlays.forEach((overlay) => { - this.updateOverlayPosition(overlay); - }); - } - - changePosition(args) { - this.textBoxX = this.textBoxX + args.X; - this.textBoxY = this.textBoxY + args.Y * -1; - - const overlays = document.querySelectorAll(".ask-box"); - overlays.forEach((overlay) => { - this.updateOverlayPosition(overlay); - }); - } - - updateOverlayPosition(overlay) { - if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; - } else { - overlay.style.left = "50%"; - overlay.style.top = "50%"; - } - } - - setMaxBoxCount(args) { - this.maxBoxCount = args.MAX; - } - - setFontSize(args) { - this.fontSize = args.SIZE + 'px'; - } - - setTextAlignment(args) { - this.textAlign = args.ALIGNMENT; - } - - setFontFamily(args) { - this.fontFamily = args.FONT; - } - - setSlider(args) { - this.minSlider = args.MIN; - this.maxSlider = args.MAX; - this.defaultSlider = args.DEFAULT; - } - - setEnable(args) { - const enableMenu = args.ENABLE_MENU; - const action = args.ACTION; - switch (enableMenu) { - case 'Button 2': - this.showCancelButton = action === 'Enabled'; - break; - case 'Button 3': - this.showButton3 = action === 'Enabled'; - break; - case 'Button 4': - this.showButton4 = action === 'Enabled'; - break; - } - } - - setInputType(args) { - this.isInputEnabled = args.ACTION; - } - - setButtonText(args) { - const buttonMenu = args.BUTTON_MENU; - const text = args.TEXT; - switch (buttonMenu) { - case 'Button 1': - this.submitButtonText = text; - break; - case 'Button 2': - this.cancelButtonText = text; - break; - case 'Button 3': - this.Button3Text = text; - break; - case 'Button 4': - this.Button4Text = text; - break; - case 'Dropdown': - this.DropdownText = text; - break; - } - } - - askAndWaitForInput(args) { - if (this.askBoxCount < this.maxBoxCount) { - return new Promise((resolve) => { - this.askAndWait(args).then(() => { - resolve(this.getUserInput()); - }); - }); - } - } - - removeAskBoxes() { - const askBoxes = document.querySelectorAll(".ask-box"); - askBoxes.forEach((box) => { - box.parentNode.removeChild(box); - }); - - if (this.askBoxPromise) { - this.askBoxPromise.resolve("removed"); - this.askBoxPromise = null; - } - this.askBoxCount = 0; - this.userInput = ''; - } - - applyEnterEffect(overlay) { - overlay.style.opacity = '1'; - overlay.style.transform = 'scale(1)'; - - let currentOpacity = 0; - let currentScale = 0; - - if (this.enterEffect !== 'None') { - if (this.enterEffect === 'fadeIn' || this.enterEffect === 'Both') { - overlay.style.opacity = '0'; - } - - if (this.enterEffect === 'growIn' || this.enterEffect === 'Both') { - overlay.style.transform = 'scale(0)'; - overlay.style.transition = 'opacity 0.3s'; - } - - const step = () => { - if ((this.enterEffect === 'fadeIn' || this.enterEffect === 'Both') && currentOpacity < 100) { - currentOpacity += this.enterSpeed; - overlay.style.opacity = `${currentOpacity}%`; - } - - if ((this.enterEffect === 'growIn' || this.enterEffect === 'Both') && currentScale < 100) { - currentScale += this.enterSpeed; - overlay.style.transform = `scale(${currentScale / 100})`; - } - - if ((this.enterEffect === 'Both' && (currentOpacity < 100 || currentScale < 100)) || - (this.enterEffect === 'growIn' && currentScale < 100) || - (this.enterEffect !== 'Both' && currentOpacity < 100)) { - requestAnimationFrame(step); - } - }; - - if (this.enterEffect === 'growIn' || this.enterEffect === 'Both') { - overlay.style.transition = 'opacity 0.3s'; - } - - requestAnimationFrame(step); - } else { - overlay.style.opacity = '1'; - } - } - - applyExitEffect(overlay) { - let currentScale = 100; - let currentOpacity = 0; - - if (this.exitEffect !== 'None') { - if (this.exitEffect === 'fadeOut') { - overlay.style.transition = 'opacity 0.5s'; - } else { - overlay.style.transition = 'transform 0.5s, opacity 0.5s'; - } - - const step = () => { - if ((this.exitEffect === 'fadeOut' || this.exitEffect === 'Both') && currentOpacity < 100) { - currentOpacity -= this.exitSpeed; - overlay.style.opacity = `${currentOpacity}%`; - } - - if ((this.exitEffect === 'shrinkOut' || this.exitEffect === 'Both') && currentScale > 0) { - currentScale -= this.exitSpeed; - overlay.style.transform = `scale(${currentScale / 100})`; - } - - if ((this.exitEffect === 'Both' && (currentOpacity > -200 || currentScale > -100)) || (this.exitEffect === 'shrinkOut' && currentScale > -100) || (this.exitEffect !== 'Both' && currentOpacity > -200)) { - requestAnimationFrame(step); - } else { - document.body.removeChild(overlay); - } - }; - - requestAnimationFrame(step); - } else { - document.body.removeChild(overlay); - } - } - - askAndWait(args) { - if (this.askBoxCount < this.maxBoxCount) { - const question = args.question; - this.isWaitingForInput = true; - this.userInput = null; - this.askBoxCount++; - if (this.askBoxPromise) { - this.askBoxPromise.resolve("removed"); - } - - this.askBoxPromise = {}; - - return new Promise((resolve) => { - this.askBoxPromise.resolve = resolve; - const overlay = document.createElement('div'); - overlay.classList.add('ask-box'); - overlay.style.position = 'fixed'; - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; - overlay.style.zIndex = "9999"; - overlay.style.backgroundColor = this.textBoxColor; - overlay.style.boxShadow = '0 0 5px rgba(0, 0, 0, 0.3)'; - overlay.style.borderRadius = this.textBoxBorderRadius + 'px'; - overlay.style.padding = '15px'; - overlay.style.fontSize = this.fontSize; - overlay.style.textAlign = this.textAlign; - overlay.style.fontFamily = this.fontFamily; - - const overlayImageContainer = document.createElement('div'); - overlayImageContainer.style.background = `url(${this.overlayImage})`; - overlayImageContainer.style.width = '100%'; - overlayImageContainer.style.height = '100%'; - overlayImageContainer.style.position = 'absolute'; - overlayImageContainer.style.top = '0'; - overlayImageContainer.style.left = '0'; - overlayImageContainer.style.zIndex = '-1'; - - if (this.forceInput !== 'Disabled') { - let overlayInput; - - if (this.forceInput === 'Enter Key') { - overlayInput = 'Enter'; - } else if (this.forceInput === 'Shift + Enter Key') { - overlayInput = 'ShiftEnter'; - } else { - overlayInput = this.forceInput; - } - - const handleKeydown = (event) => { - if ( - (overlayInput === 'ShiftEnter' && event.shiftKey && event.key === 'Enter') || (event.key === overlayInput) - ) { - this.userInput = inputField.value; - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - - } - resolve(); - this.askBoxCount--; - } - }; - - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === 'childList' && !document.contains(overlay)) { - document.removeEventListener('keydown', handleKeydown); - observer.disconnect(); - } - } - }); - - observer.observe(document.body, { childList: true }); - - document.addEventListener('keydown', handleKeydown); - } - - const questionText = document.createElement('div'); - questionText.classList.add('question'); - questionText.style.fontSize = this.fontSize; - questionText.style.marginBottom = '10px'; - questionText.style.color = this.questionColor; - questionText.textContent = question; - - const inputField = document.createElement('input'); - inputField.style.display = this.isInputEnabled ? 'block' : 'none'; - inputField.style.width = '94%'; - inputField.style.padding = '5px'; - inputField.style.fontSize = this.fontSize; - inputField.style.color = this.inputColor; - inputField.style.backgroundColor = this.inputBackgroundColor; - inputField.style.border = `1px solid ${this.inputOutlineColor}`; - inputField.style.borderRadius = this.inputBoxRadius + 'px'; - inputField.style.margin = '0 auto'; - inputField.style.textAlign = this.textAlign; - - const submitButton = document.createElement('button'); - submitButton.style.marginTop = '10px'; - submitButton.style.marginRight = '5px'; - submitButton.style.padding = '5px 10px'; - submitButton.style.backgroundColor = this.submitButtonColor; - submitButton.style.color = this.submitButtonTextColor; - submitButton.style.border = 'none'; - submitButton.style.borderRadius = this.submitButtonBorderRadius + 'px'; - submitButton.style.cursor = 'pointer'; - submitButton.textContent = this.submitButtonText; - - submitButton.addEventListener('click', () => { - if (this.isInputEnabled !== 'Disabled') { - this.userInput = inputField.value; - } else { - this.userInput = this.submitButtonText; - } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } - resolve(); - this.askBoxCount--; - }); - - const cancelButton = document.createElement('button'); - cancelButton.style.marginTop = '10px'; - cancelButton.style.marginRight = '5px'; - cancelButton.style.padding = '5px 10px'; - cancelButton.style.backgroundColor = this.cancelButtonColor; - cancelButton.style.color = this.cancelButtonTextColor; - cancelButton.style.border = 'none'; - cancelButton.style.borderRadius = this.cancelButtonBorderRadius + 'px'; - cancelButton.style.cursor = 'pointer'; - cancelButton.textContent = this.cancelButtonText; - cancelButton.style.display = this.showCancelButton ? 'inline-block' : 'none'; - - cancelButton.addEventListener('click', () => { - if (this.isInputEnabled === 'Disabled') { - this.userInput = this.cancelButtonText; - } else { - this.userInput = '' - } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } - resolve(); - this.askBoxCount--; - }); - - const Button3 = document.createElement('button'); - Button3.style.marginTop = '10px'; - Button3.style.marginRight = '5px'; - Button3.style.padding = '5px 10px'; - Button3.style.backgroundColor = this.button3Color; - Button3.style.color = this.button3TextColor; - Button3.style.border = 'none'; - Button3.style.borderRadius = this.button3BorderRadius + 'px'; - Button3.style.cursor = 'pointer'; - Button3.textContent = this.Button3Text; - Button3.style.display = this.showButton3 ? 'inline-block' : 'none'; - - Button3.addEventListener('click', () => { - if (this.isInputEnabled === 'Disabled') { - this.userInput = this.Button3Text; - } else { - this.userInput = '' - } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } - resolve(); - this.askBoxCount--; - }); - - const Button4 = document.createElement('button'); - Button4.style.marginTop = '10px'; - Button4.style.marginRight = '5px'; - Button4.style.padding = '5px 10px'; - Button4.style.backgroundColor = this.button4Color; - Button4.style.color = this.button4TextColor; - Button4.style.border = 'none'; - Button4.style.borderRadius = this.button4BorderRadius + 'px'; - Button4.style.cursor = 'pointer'; - Button4.textContent = this.Button4Text; - Button4.style.display = this.showButton4 ? 'inline-block' : 'none'; - - Button4.addEventListener('click', () => { - if (this.isInputEnabled === 'Disabled') { - this.userInput = this.Button4Text; - } else { - this.userInput = '' - } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } - resolve(); - this.askBoxCount--; - }); - - const dropdown = document.createElement('div'); - dropdown.className = 'dropdown'; - - const dropdownButton = document.createElement('button'); - dropdownButton.className = 'dropdown-button'; - dropdownButton.textContent = this.DropdownText; - dropdownButton.style.padding = '5px 10px'; - dropdownButton.style.backgroundColor = this.optionbuttonColor; - dropdownButton.style.color = this.optionbuttonTextColor; - dropdownButton.style.border = 'none'; - dropdownButton.style.borderRadius = this.optionbuttonBorderRadius + 'px'; - - const dropdownContent = document.createElement('div'); - dropdownContent.className = 'dropdown-content'; - - let isDropdownOpen = false; - - const optionList = this.optionList; - const numOfOptions = optionList.split(this.splitKey).length; - const options = this.optionList.split(this.splitKey); - for (let i = 1; i <= numOfOptions; i++) { - const optionButton = document.createElement('button'); - optionButton.style.marginRight = '5px'; - optionButton.style.marginTop = '10px'; - optionButton.style.padding = '5px 10px'; - optionButton.style.backgroundColor = this.optionbuttonColor; - optionButton.style.color = this.optionbuttonTextColor; - optionButton.style.border = 'none'; - optionButton.style.borderRadius = this.optionbuttonBorderRadius + 'px'; - optionButton.textContent = `${options[i - 1]}`; - optionButton.style.filter = 'brightness(1)'; - - optionButton.addEventListener('click', () => { - inputField.value = `${options[i - 1]}`; - - for (let j = 0; j < numOfOptions; j++) { - const otherButton = dropdownContent.children[j]; - otherButton.style.filter = 'brightness(1)'; - } - - optionButton.style.filter = 'brightness(1.5)'; - }); - dropdownContent.appendChild(optionButton); - } - - dropdownButton.addEventListener('mouseover', () => { - if (!isDropdownOpen) { - overlay.insertBefore(dropdownContent, submitButton); - isDropdownOpen = true; - } - }); - - overlay.addEventListener('mouseleave', () => { - if (isDropdownOpen) { - overlay.removeChild(dropdownContent); - isDropdownOpen = false; - } - }); - - const sliderContainer = document.createElement('div'); - sliderContainer.classList.add('slider-container'); - - const slider = document.createElement('input'); - slider.type = 'range'; - slider.min = this.minSlider; - slider.max = this.maxSlider; - slider.value = this.defaultSlider; - - sliderContainer.appendChild(slider); - - const valueDisplay = document.createElement('span'); - valueDisplay.classList.add('slider-value'); - sliderContainer.appendChild(valueDisplay); - valueDisplay.style.color = this.questionColor; - valueDisplay.textContent = slider.value; - - slider.addEventListener('input', () => { - valueDisplay.textContent = slider.value; - inputField.value = valueDisplay.textContent; - }); - - overlay.appendChild(questionText); - - if (this.isInputEnabled !== 'Disabled') { - if (this.isInputEnabled === 'Enabled') { - overlay.appendChild(inputField); - } else if (this.isInputEnabled === 'Dropdown'){ - dropdown.appendChild(dropdownButton); - overlay.appendChild(dropdown); - } else { - overlay.appendChild(sliderContainer); - overlay.appendChild(valueDisplay); - overlay.appendChild(document.createElement('br')); - } - } - - overlay.appendChild(submitButton); - overlay.appendChild(cancelButton); - overlay.appendChild(Button3); - overlay.appendChild(Button4); - overlay.appendChild(overlayImageContainer); - - - document.body.appendChild(overlay); - inputField.focus(); - - if (this.enterEffect) { - this.applyEnterEffect(overlay); - } else { - overlay.style.opacity = '1'; - overlay.style.transform = 'scale(1)'; - } - - const resizeHandler = () => { - if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; - } else { - overlay.style.left = "50%"; - overlay.style.top = "50%"; - } - }; - - document.addEventListener("fullscreenchange", resizeHandler); - document.addEventListener("webkitfullscreenchange", resizeHandler); - document.addEventListener("mozfullscreenchange", resizeHandler); - document.addEventListener("MSFullscreenChange", resizeHandler); - - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === "childList" && !document.contains(overlay)) { - document.removeEventListener("fullscreenchange", resizeHandler); - document.removeEventListener("webkitfullscreenchange", resizeHandler); - document.removeEventListener("mozfullscreenchange", resizeHandler); - document.removeEventListener("MSFullscreenChange", resizeHandler); - observer.disconnect(); - } - } - }); - - observer.observe(document.body, { childList: true }); - document.body.appendChild(overlay); - inputField.focus(); - }); - } - } - - getUserInput() { - return this.userInput; - } - - getBoxCount() { - return this.askBoxCount; - } - - getMaxCount() { - return this.maxBoxCount; - } - - getXpos() { - return this.textBoxX; - } - - getYpos() { - return this.textBoxY; - } - - setSubmitEvent(args) { - this.forceInput = args.ENTER; - } - - setDropdown(args) { - this.optionList = args.DROPDOWN - this.splitKey = args.SPLITTER - } - - setEnterSpeed(args) { - this.enterSpeed = Math.abs(args.SPEED) - if (this.enterSpeed < 1) { - this.enterSpeed = 1 - } - } - - setExitSpeed(args) { - this.exitSpeed = Math.abs(args.SPEED) - if (this.exitSpeed < 1) { - this.exitSpeed = 1 - } - } - - setImage(args) { - this.overlayImage = args.IMAGE; - } -} - - Scratch.extensions.register(new BetterInputSP()); -})(Scratch); diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js new file mode 100644 index 0000000000..c7efdb598d --- /dev/null +++ b/extensions/SharkPool/BetterInput.js @@ -0,0 +1,1305 @@ +/* + * This extension was made by SharkPool + * Version 2.0 (Sliders, Bug Fixes, Better Force Input, and more Fonts) + * Next Update: None right now + * Do NOT delete these comments + */ + +(function (Scratch) { + "use strict"; + + if (!Scratch.extensions.unsandboxed) { + throw new Error("Better Input must run unsandboxed"); + } + + const menuIconURI = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; + + const blockIconURI = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + + const formatIcon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + + const colorIcon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; + + const effectIcon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + + class BetterInputSP { + constructor() { + this.isWaitingForInput = false; + this.userInput = ""; + this.fontSize = "14px"; + this.questionColor = "#000000"; + this.inputColor = "#000000"; + this.textBoxColor = "#ffffff"; + this.inputBackgroundColor = "#ffffff"; + this.inputOutlineColor = "#000000"; + this.textAlign = "left"; + this.fontFamily = "Arial"; + this.showCancelButton = true; + this.showButton3 = false; + this.showButton4 = false; + this.submitButtonText = "Submit"; + this.cancelButtonText = "Cancel"; + this.Button3Text = "Okay"; + this.Button4Text = "No"; + this.DropdownText = "Dropdown"; + this.submitButtonColor = "#0074D9"; + this.cancelButtonColor = "#d9534f"; + this.button3Color = "#0074D9"; + this.button4Color = "#d9534f"; + this.optionbuttonColor = "#5f5f5f"; + this.cancelButtonBorderRadius = 5; + this.submitButtonBorderRadius = 5; + this.button3BorderRadius = 5; + this.button4BorderRadius = 5; + this.optionbuttonBorderRadius = 5; + this.submitButtonTextColor = "#ffffff"; + this.cancelButtonTextColor = "#ffffff"; + this.button3TextColor = "#ffffff"; + this.button4TextColor = "#ffffff"; + this.optionbuttonTextColor = "#ffffff"; + this.textBoxBorderRadius = 5; + this.inputBoxRadius = 4; + this.isInputEnabled = "Enabled"; + this.textBoxX = 0; + this.textBoxY = 0; + this.askBoxCount = 0; + this.maxBoxCount = 1; + this.forceInput = "Disabled"; + this.overlayInput = null; + this.overlayImage = null; + this.optionList = "Option 1,Option 2,Option 3"; + this.splitKey = ","; + this.minSlider = "0"; + this.maxSlider = "100"; + this.defaultSlider = "50"; + this.enterSpeed = 10; + this.exitSpeed = 10; + } + + getInfo() { + return { + id: "BetterInputSP", + name: "Better Input", + color1: "#9400ff", + menuIconURI, + blockIconURI, + blocks: [ + { + blockType: Scratch.BlockType.LABEL, + text: "Text Blocks", + }, + { + opcode: "askAndWait", + blockType: Scratch.BlockType.COMMAND, + text: "ask [question] and wait", + arguments: { + question: { + type: Scratch.ArgumentType.STRING, + defaultValue: "What is your name?", + }, + }, + }, + { + opcode: "askAndWaitForInput", + blockType: Scratch.BlockType.REPORTER, + text: "ask [question] and wait", + arguments: { + question: { + type: Scratch.ArgumentType.STRING, + defaultValue: "What is your name?", + }, + }, + }, + { + opcode: "getUserInput", + blockType: Scratch.BlockType.REPORTER, + text: "user input", + }, + { + opcode: "removeAskBoxes", + blockType: Scratch.BlockType.COMMAND, + text: "remove all ask boxes", + }, + { + opcode: "setButtonText", + blockType: Scratch.BlockType.COMMAND, + text: "set [BUTTON_MENU] text to [TEXT]", + arguments: { + BUTTON_MENU: { + type: Scratch.ArgumentType.STRING, + menu: "buttonMenu", + defaultValue: "Button 1", + }, + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Submit", + }, + }, + }, + { + opcode: "setDropdown", + blockType: Scratch.BlockType.COMMAND, + text: "set dropdown options to list: [DROPDOWN] split by [SPLITTER]", + arguments: { + DROPDOWN: { + type: Scratch.ArgumentType.STRING, + defaultValue: "option 1,option 2,option 3", + }, + SPLITTER: { + type: Scratch.ArgumentType.STRING, + defaultValue: ",", + }, + }, + }, + { + opcode: "setSlider", + blockType: Scratch.BlockType.COMMAND, + text: "set slider to min: [MIN] max: [MAX] default: [DEFAULT]", + arguments: { + MIN: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "0", + }, + MAX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "100", + }, + DEFAULT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "50", + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: "Formatting", + }, + { + opcode: "setTextAlignment", + blockType: Scratch.BlockType.COMMAND, + text: "set alignment to [ALIGNMENT]", + blockIconURI: formatIcon, + arguments: { + ALIGNMENT: { + type: Scratch.ArgumentType.STRING, + menu: "alignmentMenu", + defaultValue: "left", + }, + }, + }, + { + opcode: "setFontFamily", + blockType: Scratch.BlockType.COMMAND, + text: "set font to [FONT]", + blockIconURI: formatIcon, + arguments: { + FONT: { + type: Scratch.ArgumentType.STRING, + menu: "fontMenu", + defaultValue: "Arial", + }, + }, + }, + { + opcode: "setInputType", + blockType: Scratch.BlockType.COMMAND, + text: "set Input Box to be [ACTION]", + blockIconURI: formatIcon, + arguments: { + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "inputActionMenu", + defaultValue: "Enabled", + }, + }, + }, + { + opcode: "setEnable", + blockType: Scratch.BlockType.COMMAND, + text: "set [ENABLE_MENU] to be [ACTION]", + blockIconURI: formatIcon, + arguments: { + ENABLE_MENU: { + type: Scratch.ArgumentType.STRING, + menu: "enableMenu", + defaultValue: "Button 2", + }, + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "buttonActionMenu", + defaultValue: "Enabled", + }, + }, + }, + { + opcode: "setFontSize", + blockType: Scratch.BlockType.COMMAND, + text: "set font size to [SIZE]", + blockIconURI: formatIcon, + arguments: { + SIZE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 14, + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: "Positioning", + }, + { + opcode: "setPrePosition", + blockType: Scratch.BlockType.COMMAND, + text: "preset textbox position to x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + { + opcode: "setPosition", + blockType: Scratch.BlockType.COMMAND, + text: "set textbox position to x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + { + opcode: "changePosition", + blockType: Scratch.BlockType.COMMAND, + text: "change textbox position by x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + { + opcode: "getXpos", + blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, + text: "x position", + }, + { + opcode: "getYpos", + blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, + text: "y position", + }, + { + blockType: Scratch.BlockType.LABEL, + text: "Visual Settings", + }, + { + opcode: "setColorSettings", + blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to [COLOR]", + blockIconURI: colorIcon, + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "colorSettingsMenu", + defaultValue: "Question", + }, + COLOR: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#000000", + }, + }, + }, + { + opcode: "setBorderRadius", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] border radius to [VALUE]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, + VALUE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + }, + }, + }, + { + opcode: "setImage", + blockType: Scratch.BlockType.COMMAND, + text: "set background image to [IMAGE]", + blockIconURI: colorIcon, + arguments: { + IMAGE: { + type: Scratch.ArgumentType.STRING, + defaultValue: "input-url-or-uri-here", + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: "Effects", + }, + { + opcode: "setEnterEffect", + blockType: Scratch.BlockType.COMMAND, + text: "set enter effect to [ENTER_EFFECT]", + blockIconURI: effectIcon, + arguments: { + ENTER_EFFECT: { + type: Scratch.ArgumentType.STRING, + menu: "enterEffectMenu", + defaultValue: "None", + }, + }, + }, + { + opcode: "setEnterSpeed", + blockType: Scratch.BlockType.COMMAND, + text: "set enter effect speed to [SPEED]", + blockIconURI: effectIcon, + arguments: { + SPEED: { + type: Scratch.ArgumentType.STRING, + defaultValue: "10", + }, + }, + }, + { + opcode: "setExitEffect", + blockType: Scratch.BlockType.COMMAND, + text: "set exit effect to [EXIT_EFFECT]", + blockIconURI: effectIcon, + arguments: { + EXIT_EFFECT: { + type: Scratch.ArgumentType.STRING, + menu: "exitEffectMenu", + defaultValue: "None", + }, + }, + }, + { + opcode: "setExitSpeed", + blockType: Scratch.BlockType.COMMAND, + text: "set exit effect speed to [SPEED]", + blockIconURI: effectIcon, + arguments: { + SPEED: { + type: Scratch.ArgumentType.STRING, + defaultValue: "10", + }, + }, + }, + { + blockType: Scratch.BlockType.LABEL, + text: "Operations", + }, + { + opcode: "setSubmitEvent", + blockType: Scratch.BlockType.COMMAND, + text: "set force input to [ENTER]", + arguments: { + ENTER: { + type: Scratch.ArgumentType.STRING, + menu: "enterMenu", + defaultValue: "Disabled", + }, + }, + }, + { + opcode: "setMaxBoxCount", + blockType: Scratch.BlockType.COMMAND, + text: "set max box count to: [MAX]", + arguments: { + MAX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1, + }, + }, + }, + { + opcode: "getBoxCount", + blockType: Scratch.BlockType.REPORTER, + text: "box count", + }, + { + opcode: "getMaxCount", + blockType: Scratch.BlockType.REPORTER, + text: "box limit", + }, + ], + menus: { + alignmentMenu: ["left", "right", "center"], + fontMenu: [ + "Arial", + "Times New Roman", + "Comic Sans MS", + "Verdana", + "Courier New", + "Impact", + "Cursive", + "Lucida Console", + "Scratch", + "Arial Black", + "Calibri", + "Consolas", + "Handwriting", + "Marker", + "Curly", + "Pixel", + "MS PGothic", + "Malgun Gothic", + "Microsoft YaHei", + ], + buttonActionMenu: ["Enabled", "Disabled"], + inputActionMenu: ["Enabled", "Disabled", "Dropdown", "Slider"], + enterEffectMenu: ["None", "Fade in", "Grow", "Both"], + exitEffectMenu: ["None", "Fade out", "Shrink", "Both"], + buttonMenu: [ + "Button 1", + "Button 2", + "Button 3", + "Button 4", + "Dropdown", + ], + enableMenu: ["Button 2", "Button 3", "Button 4"], + elementMenu: [ + "Textbox", + "Input Box", + "Button 1", + "Button 2", + "Button 3", + "Button 4", + "Dropdown Buttons", + ], + colorSettingsMenu: [ + "Question", + "Input Text", + "Textbox", + "Input Background", + "Input Outline", + "Button 1", + "Button 2", + "Button 3", + "Button 4", + "Dropdown Buttons", + "Button 1 Text", + "Button 2 Text", + "Button 3 Text", + "Button 4 Text", + "Dropdown Text", + ], + enterMenu: { + acceptReporters: true, + items: ["Disabled", "Enter Key", "Shift + Enter Key"], + }, + }, + }; + } + + setColorSettings(args) { + const colorType = args.COLOR_TYPE; + const colorValue = args.COLOR; + + switch (colorType) { + case "Question": + this.questionColor = colorValue; + break; + case "Input Text": + this.inputColor = colorValue; + break; + case "Textbox": + this.textBoxColor = colorValue; + this.overlayImage = null; + break; + case "Input Background": + this.inputBackgroundColor = colorValue; + break; + case "Input Outline": + this.inputOutlineColor = colorValue; + break; + case "Button 1": + this.submitButtonColor = colorValue; + break; + case "Button 2": + this.cancelButtonColor = colorValue; + break; + case "Button 3": + this.button3Color = colorValue; + break; + case "Button 4": + this.button4Color = colorValue; + break; + case "Dropdown Buttons": + this.optionbuttonColor = colorValue; + break; + case "Slider": + this.sliderColor = colorValue; + break; + case "Button 1 Text": + this.submitButtonTextColor = colorValue; + break; + case "Button 2 Text": + this.cancelButtonTextColor = colorValue; + break; + case "Button 3 Text": + this.button3TextColor = colorValue; + break; + case "Button 4 Text": + this.button4TextColor = colorValue; + break; + case "Dropdown Text": + this.optionbuttonTextColor = colorValue; + break; + } + } + + setBorderRadius(args) { + const element = args.ELEMENT; + let value = args.VALUE; + + if (value < 0) { + value = 0; + } + + switch (element) { + case "Textbox": + this.textBoxBorderRadius = value; + break; + case "Button 1": + this.cancelButtonBorderRadius = value; + break; + case "Button 2": + this.submitButtonBorderRadius = value; + break; + case "Button 3": + this.button3BorderRadius = value; + break; + case "Button 4": + this.button4BorderRadius = value; + break; + case "Input Box": + this.inputBoxRadius = value; + break; + case "Dropdown Buttons": + this.optionbuttonBorderRadius = value; + break; + case "Slider": + this.sliderBorderRadius = value; + break; + } + } + + setEnterEffect(args) { + const enterEffect = args.ENTER_EFFECT; + switch (enterEffect) { + case "None": + this.enterEffect = null; + break; + case "Fade in": + this.enterEffect = "fadeIn"; + break; + case "Grow": + this.enterEffect = "growIn"; + break; + case "Both": + this.enterEffect = "Both"; + break; + } + } + + setExitEffect(args) { + const exitEffect = args.EXIT_EFFECT; + switch (exitEffect) { + case "None": + this.exitEffect = null; + break; + case "Fade out": + this.exitEffect = "fadeOut"; + break; + case "Shrink": + this.exitEffect = "shrinkOut"; + break; + case "Both": + this.exitEffect = "Both"; + break; + } + } + + setPrePosition(args) { + this.textBoxX = args.X; + this.textBoxY = args.Y * -1; + } + + setPosition(args) { + this.textBoxX = args.X; + this.textBoxY = args.Y * -1; + + const overlays = document.querySelectorAll(".ask-box"); + overlays.forEach((overlay) => { + this.updateOverlayPosition(overlay); + }); + } + + changePosition(args) { + this.textBoxX = this.textBoxX + args.X; + this.textBoxY = this.textBoxY + args.Y * -1; + + const overlays = document.querySelectorAll(".ask-box"); + overlays.forEach((overlay) => { + this.updateOverlayPosition(overlay); + }); + } + + updateOverlayPosition(overlay) { + if (this.textBoxX !== null && this.textBoxY !== null) { + overlay.style.left = `${41 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } + } + + setMaxBoxCount(args) { + this.maxBoxCount = args.MAX; + } + + setFontSize(args) { + this.fontSize = args.SIZE + "px"; + } + + setTextAlignment(args) { + this.textAlign = args.ALIGNMENT; + } + + setFontFamily(args) { + this.fontFamily = args.FONT; + } + + setSlider(args) { + this.minSlider = args.MIN; + this.maxSlider = args.MAX; + this.defaultSlider = args.DEFAULT; + } + + setEnable(args) { + const enableMenu = args.ENABLE_MENU; + const action = args.ACTION; + switch (enableMenu) { + case "Button 2": + this.showCancelButton = action === "Enabled"; + break; + case "Button 3": + this.showButton3 = action === "Enabled"; + break; + case "Button 4": + this.showButton4 = action === "Enabled"; + break; + } + } + + setInputType(args) { + this.isInputEnabled = args.ACTION; + } + + setButtonText(args) { + const buttonMenu = args.BUTTON_MENU; + const text = args.TEXT; + switch (buttonMenu) { + case "Button 1": + this.submitButtonText = text; + break; + case "Button 2": + this.cancelButtonText = text; + break; + case "Button 3": + this.Button3Text = text; + break; + case "Button 4": + this.Button4Text = text; + break; + case "Dropdown": + this.DropdownText = text; + break; + } + } + + askAndWaitForInput(args) { + if (this.askBoxCount < this.maxBoxCount) { + return new Promise((resolve) => { + this.askAndWait(args).then(() => { + resolve(this.getUserInput()); + }); + }); + } + } + + removeAskBoxes() { + const askBoxes = document.querySelectorAll(".ask-box"); + askBoxes.forEach((box) => { + box.parentNode.removeChild(box); + }); + + if (this.askBoxPromise) { + this.askBoxPromise.resolve("removed"); + this.askBoxPromise = null; + } + this.askBoxCount = 0; + this.userInput = ""; + } + + applyEnterEffect(overlay) { + overlay.style.opacity = "1"; + overlay.style.transform = "scale(1)"; + + let currentOpacity = 0; + let currentScale = 0; + + if (this.enterEffect !== "None") { + if (this.enterEffect === "fadeIn" || this.enterEffect === "Both") { + overlay.style.opacity = "0"; + } + + if (this.enterEffect === "growIn" || this.enterEffect === "Both") { + overlay.style.transform = "scale(0)"; + overlay.style.transition = "opacity 0.3s"; + } + + const step = () => { + if ( + (this.enterEffect === "fadeIn" || this.enterEffect === "Both") && + currentOpacity < 100 + ) { + currentOpacity += this.enterSpeed; + overlay.style.opacity = `${currentOpacity}%`; + } + + if ( + (this.enterEffect === "growIn" || this.enterEffect === "Both") && + currentScale < 100 + ) { + currentScale += this.enterSpeed; + overlay.style.transform = `scale(${currentScale / 100})`; + } + + if ( + (this.enterEffect === "Both" && + (currentOpacity < 100 || currentScale < 100)) || + (this.enterEffect === "growIn" && currentScale < 100) || + (this.enterEffect !== "Both" && currentOpacity < 100) + ) { + requestAnimationFrame(step); + } + }; + + if (this.enterEffect === "growIn" || this.enterEffect === "Both") { + overlay.style.transition = "opacity 0.3s"; + } + + requestAnimationFrame(step); + } else { + overlay.style.opacity = "1"; + } + } + + applyExitEffect(overlay) { + let currentScale = 100; + let currentOpacity = 0; + + if (this.exitEffect !== "None") { + if (this.exitEffect === "fadeOut") { + overlay.style.transition = "opacity 0.5s"; + } else { + overlay.style.transition = "transform 0.5s, opacity 0.5s"; + } + + const step = () => { + if ( + (this.exitEffect === "fadeOut" || this.exitEffect === "Both") && + currentOpacity < 100 + ) { + currentOpacity -= this.exitSpeed; + overlay.style.opacity = `${currentOpacity}%`; + } + + if ( + (this.exitEffect === "shrinkOut" || this.exitEffect === "Both") && + currentScale > 0 + ) { + currentScale -= this.exitSpeed; + overlay.style.transform = `scale(${currentScale / 100})`; + } + + if ( + (this.exitEffect === "Both" && + (currentOpacity > -200 || currentScale > -100)) || + (this.exitEffect === "shrinkOut" && currentScale > -100) || + (this.exitEffect !== "Both" && currentOpacity > -200) + ) { + requestAnimationFrame(step); + } else { + document.body.removeChild(overlay); + } + }; + + requestAnimationFrame(step); + } else { + document.body.removeChild(overlay); + } + } + + askAndWait(args) { + if (this.askBoxCount < this.maxBoxCount) { + const question = args.question; + this.isWaitingForInput = true; + this.userInput = null; + this.askBoxCount++; + if (this.askBoxPromise) { + this.askBoxPromise.resolve("removed"); + } + + this.askBoxPromise = {}; + + return new Promise((resolve) => { + this.askBoxPromise.resolve = resolve; + const overlay = document.createElement("div"); + overlay.classList.add("ask-box"); + overlay.style.position = "fixed"; + overlay.style.left = `${41 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; + overlay.style.zIndex = "9999"; + overlay.style.backgroundColor = this.textBoxColor; + overlay.style.boxShadow = "0 0 5px rgba(0, 0, 0, 0.3)"; + overlay.style.borderRadius = this.textBoxBorderRadius + "px"; + overlay.style.padding = "15px"; + overlay.style.fontSize = this.fontSize; + overlay.style.textAlign = this.textAlign; + overlay.style.fontFamily = this.fontFamily; + + const overlayImageContainer = document.createElement("div"); + overlayImageContainer.style.background = `url(${this.overlayImage})`; + overlayImageContainer.style.width = "100%"; + overlayImageContainer.style.height = "100%"; + overlayImageContainer.style.position = "absolute"; + overlayImageContainer.style.top = "0"; + overlayImageContainer.style.left = "0"; + overlayImageContainer.style.zIndex = "-1"; + + if (this.forceInput !== "Disabled") { + let overlayInput; + + if (this.forceInput === "Enter Key") { + overlayInput = "Enter"; + } else if (this.forceInput === "Shift + Enter Key") { + overlayInput = "ShiftEnter"; + } else { + overlayInput = this.forceInput; + } + + const handleKeydown = (event) => { + if ( + (overlayInput === "ShiftEnter" && + event.shiftKey && + event.key === "Enter") || + event.key === overlayInput + ) { + this.userInput = inputField.value; + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + } + resolve(); + this.askBoxCount--; + } + }; + + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if ( + mutation.type === "childList" && + !document.contains(overlay) + ) { + document.removeEventListener("keydown", handleKeydown); + observer.disconnect(); + } + } + }); + + observer.observe(document.body, { childList: true }); + + document.addEventListener("keydown", handleKeydown); + } + + const questionText = document.createElement("div"); + questionText.classList.add("question"); + questionText.style.fontSize = this.fontSize; + questionText.style.marginBottom = "10px"; + questionText.style.color = this.questionColor; + questionText.textContent = question; + + const inputField = document.createElement("input"); + inputField.style.display = this.isInputEnabled ? "block" : "none"; + inputField.style.width = "94%"; + inputField.style.padding = "5px"; + inputField.style.fontSize = this.fontSize; + inputField.style.color = this.inputColor; + inputField.style.backgroundColor = this.inputBackgroundColor; + inputField.style.border = `1px solid ${this.inputOutlineColor}`; + inputField.style.borderRadius = this.inputBoxRadius + "px"; + inputField.style.margin = "0 auto"; + inputField.style.textAlign = this.textAlign; + + const submitButton = document.createElement("button"); + submitButton.style.marginTop = "10px"; + submitButton.style.marginRight = "5px"; + submitButton.style.padding = "5px 10px"; + submitButton.style.backgroundColor = this.submitButtonColor; + submitButton.style.color = this.submitButtonTextColor; + submitButton.style.border = "none"; + submitButton.style.borderRadius = + this.submitButtonBorderRadius + "px"; + submitButton.style.cursor = "pointer"; + submitButton.textContent = this.submitButtonText; + + submitButton.addEventListener("click", () => { + if (this.isInputEnabled !== "Disabled") { + this.userInput = inputField.value; + } else { + this.userInput = this.submitButtonText; + } + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + } + resolve(); + this.askBoxCount--; + }); + + const cancelButton = document.createElement("button"); + cancelButton.style.marginTop = "10px"; + cancelButton.style.marginRight = "5px"; + cancelButton.style.padding = "5px 10px"; + cancelButton.style.backgroundColor = this.cancelButtonColor; + cancelButton.style.color = this.cancelButtonTextColor; + cancelButton.style.border = "none"; + cancelButton.style.borderRadius = + this.cancelButtonBorderRadius + "px"; + cancelButton.style.cursor = "pointer"; + cancelButton.textContent = this.cancelButtonText; + cancelButton.style.display = this.showCancelButton + ? "inline-block" + : "none"; + + cancelButton.addEventListener("click", () => { + if (this.isInputEnabled === "Disabled") { + this.userInput = this.cancelButtonText; + } else { + this.userInput = ""; + } + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + } + resolve(); + this.askBoxCount--; + }); + + const Button3 = document.createElement("button"); + Button3.style.marginTop = "10px"; + Button3.style.marginRight = "5px"; + Button3.style.padding = "5px 10px"; + Button3.style.backgroundColor = this.button3Color; + Button3.style.color = this.button3TextColor; + Button3.style.border = "none"; + Button3.style.borderRadius = this.button3BorderRadius + "px"; + Button3.style.cursor = "pointer"; + Button3.textContent = this.Button3Text; + Button3.style.display = this.showButton3 ? "inline-block" : "none"; + + Button3.addEventListener("click", () => { + if (this.isInputEnabled === "Disabled") { + this.userInput = this.Button3Text; + } else { + this.userInput = ""; + } + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + } + resolve(); + this.askBoxCount--; + }); + + const Button4 = document.createElement("button"); + Button4.style.marginTop = "10px"; + Button4.style.marginRight = "5px"; + Button4.style.padding = "5px 10px"; + Button4.style.backgroundColor = this.button4Color; + Button4.style.color = this.button4TextColor; + Button4.style.border = "none"; + Button4.style.borderRadius = this.button4BorderRadius + "px"; + Button4.style.cursor = "pointer"; + Button4.textContent = this.Button4Text; + Button4.style.display = this.showButton4 ? "inline-block" : "none"; + + Button4.addEventListener("click", () => { + if (this.isInputEnabled === "Disabled") { + this.userInput = this.Button4Text; + } else { + this.userInput = ""; + } + this.isWaitingForInput = false; + if (this.exitEffect) { + this.applyExitEffect(overlay); + } else { + document.body.removeChild(overlay); + } + resolve(); + this.askBoxCount--; + }); + + const dropdown = document.createElement("div"); + dropdown.className = "dropdown"; + + const dropdownButton = document.createElement("button"); + dropdownButton.className = "dropdown-button"; + dropdownButton.textContent = this.DropdownText; + dropdownButton.style.padding = "5px 10px"; + dropdownButton.style.backgroundColor = this.optionbuttonColor; + dropdownButton.style.color = this.optionbuttonTextColor; + dropdownButton.style.border = "none"; + dropdownButton.style.borderRadius = + this.optionbuttonBorderRadius + "px"; + + const dropdownContent = document.createElement("div"); + dropdownContent.className = "dropdown-content"; + + let isDropdownOpen = false; + + const optionList = this.optionList; + const numOfOptions = optionList.split(this.splitKey).length; + const options = this.optionList.split(this.splitKey); + for (let i = 1; i <= numOfOptions; i++) { + const optionButton = document.createElement("button"); + optionButton.style.marginRight = "5px"; + optionButton.style.marginTop = "10px"; + optionButton.style.padding = "5px 10px"; + optionButton.style.backgroundColor = this.optionbuttonColor; + optionButton.style.color = this.optionbuttonTextColor; + optionButton.style.border = "none"; + optionButton.style.borderRadius = + this.optionbuttonBorderRadius + "px"; + optionButton.textContent = `${options[i - 1]}`; + optionButton.style.filter = "brightness(1)"; + + optionButton.addEventListener("click", () => { + inputField.value = `${options[i - 1]}`; + + for (let j = 0; j < numOfOptions; j++) { + const otherButton = dropdownContent.children[j]; + otherButton.style.filter = "brightness(1)"; + } + + optionButton.style.filter = "brightness(1.5)"; + }); + dropdownContent.appendChild(optionButton); + } + + dropdownButton.addEventListener("mouseover", () => { + if (!isDropdownOpen) { + overlay.insertBefore(dropdownContent, submitButton); + isDropdownOpen = true; + } + }); + + overlay.addEventListener("mouseleave", () => { + if (isDropdownOpen) { + overlay.removeChild(dropdownContent); + isDropdownOpen = false; + } + }); + + const sliderContainer = document.createElement("div"); + sliderContainer.classList.add("slider-container"); + + const slider = document.createElement("input"); + slider.type = "range"; + slider.min = this.minSlider; + slider.max = this.maxSlider; + slider.value = this.defaultSlider; + + sliderContainer.appendChild(slider); + + const valueDisplay = document.createElement("span"); + valueDisplay.classList.add("slider-value"); + sliderContainer.appendChild(valueDisplay); + valueDisplay.style.color = this.questionColor; + valueDisplay.textContent = slider.value; + + slider.addEventListener("input", () => { + valueDisplay.textContent = slider.value; + inputField.value = valueDisplay.textContent; + }); + + overlay.appendChild(questionText); + + if (this.isInputEnabled !== "Disabled") { + if (this.isInputEnabled === "Enabled") { + overlay.appendChild(inputField); + } else if (this.isInputEnabled === "Dropdown") { + dropdown.appendChild(dropdownButton); + overlay.appendChild(dropdown); + } else { + overlay.appendChild(sliderContainer); + overlay.appendChild(valueDisplay); + overlay.appendChild(document.createElement("br")); + } + } + + overlay.appendChild(submitButton); + overlay.appendChild(cancelButton); + overlay.appendChild(Button3); + overlay.appendChild(Button4); + overlay.appendChild(overlayImageContainer); + + document.body.appendChild(overlay); + inputField.focus(); + + if (this.enterEffect) { + this.applyEnterEffect(overlay); + } else { + overlay.style.opacity = "1"; + overlay.style.transform = "scale(1)"; + } + + const resizeHandler = () => { + if (this.textBoxX !== null && this.textBoxY !== null) { + overlay.style.left = `${41 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } + }; + + document.addEventListener("fullscreenchange", resizeHandler); + document.addEventListener("webkitfullscreenchange", resizeHandler); + document.addEventListener("mozfullscreenchange", resizeHandler); + document.addEventListener("MSFullscreenChange", resizeHandler); + + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if ( + mutation.type === "childList" && + !document.contains(overlay) + ) { + document.removeEventListener("fullscreenchange", resizeHandler); + document.removeEventListener( + "webkitfullscreenchange", + resizeHandler, + ); + document.removeEventListener( + "mozfullscreenchange", + resizeHandler, + ); + document.removeEventListener( + "MSFullscreenChange", + resizeHandler, + ); + observer.disconnect(); + } + } + }); + + observer.observe(document.body, { childList: true }); + document.body.appendChild(overlay); + inputField.focus(); + }); + } + } + + getUserInput() { + return this.userInput; + } + + getBoxCount() { + return this.askBoxCount; + } + + getMaxCount() { + return this.maxBoxCount; + } + + getXpos() { + return this.textBoxX; + } + + getYpos() { + return this.textBoxY; + } + + setSubmitEvent(args) { + this.forceInput = args.ENTER; + } + + setDropdown(args) { + this.optionList = args.DROPDOWN; + this.splitKey = args.SPLITTER; + } + + setEnterSpeed(args) { + this.enterSpeed = Math.abs(args.SPEED); + if (this.enterSpeed < 1) { + this.enterSpeed = 1; + } + } + + setExitSpeed(args) { + this.exitSpeed = Math.abs(args.SPEED); + if (this.exitSpeed < 1) { + this.exitSpeed = 1; + } + } + + setImage(args) { + this.overlayImage = args.IMAGE; + } + } + + Scratch.extensions.register(new BetterInputSP()); +})(Scratch); From 99f027fdf6453f95258009d2532fec7008c71746 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Fri, 18 Aug 2023 23:57:17 -0700 Subject: [PATCH 09/46] Update BetterInput.js Fixes n' new stuff --- extensions/SharkPool/BetterInput.js | 650 ++++++++++++++++------------ 1 file changed, 367 insertions(+), 283 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index c7efdb598d..f67efe98b7 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,7 +1,7 @@ /* * This extension was made by SharkPool - * Version 2.0 (Sliders, Bug Fixes, Better Force Input, and more Fonts) - * Next Update: None right now + * Version 2.1 (Fixes, Booleans, More Customization, Rotation, More Effects, and Performance Updates) + * Next Update: Image Setting Additions * Do NOT delete these comments */ @@ -30,6 +30,7 @@ class BetterInputSP { constructor() { this.isWaitingForInput = false; + this.isDropdownOpen = false; this.userInput = ""; this.fontSize = "14px"; this.questionColor = "#000000"; @@ -42,6 +43,7 @@ this.showCancelButton = true; this.showButton3 = false; this.showButton4 = false; + this.shadowEnabled = true; this.submitButtonText = "Submit"; this.cancelButtonText = "Cancel"; this.Button3Text = "Okay"; @@ -74,11 +76,25 @@ this.overlayImage = null; this.optionList = "Option 1,Option 2,Option 3"; this.splitKey = ","; - this.minSlider = "0"; - this.maxSlider = "100"; - this.defaultSlider = "50"; + this.minSlider = 0; + this.maxSlider = 100; + this.defaultSlider = 50; this.enterSpeed = 10; this.exitSpeed = 10; + this.activeOverlays = []; + this.Blur = 0; + this.Brightness = 100; + this.Opacity = 100; + this.Invert = 0; + this.Saturation = 100; + this.Hue = 0; + this.Sepia = 0; + this.Contrast = 100; + this.Scale = 100; + this.SkewX = 0; + this.SkewY = 0; + this.Rotation = 90; + this.Timeout = 0; } getInfo() { @@ -312,6 +328,36 @@ blockIconURI: formatIcon, text: "y position", }, + { + opcode: "setDirection", + blockType: Scratch.BlockType.COMMAND, + text: "set direction to [ROTATE]", + blockIconURI: formatIcon, + arguments: { + ROTATE: { + type: Scratch.ArgumentType.ANGLE, + defaultValue: 90, + }, + }, + }, + { + opcode: "changeDirection", + blockType: Scratch.BlockType.COMMAND, + text: "change direction by [ROTATE]", + blockIconURI: formatIcon, + arguments: { + ROTATE: { + type: Scratch.ArgumentType.ANGLE, + defaultValue: 15, + }, + }, + }, + { + opcode: "reportDirection", + blockType: Scratch.BlockType.REPORTER, + text: "direction", + blockIconURI: formatIcon, + }, { blockType: Scratch.BlockType.LABEL, text: "Visual Settings", @@ -367,59 +413,90 @@ text: "Effects", }, { - opcode: "setEnterEffect", + opcode: "resetEffect", + blockType: Scratch.BlockType.COMMAND, + text: "reset effects", + blockIconURI: effectIcon, + }, + { + opcode: "setEffect", blockType: Scratch.BlockType.COMMAND, - text: "set enter effect to [ENTER_EFFECT]", + text: "set effect [EFFECT] to [AMT]", blockIconURI: effectIcon, arguments: { - ENTER_EFFECT: { + EFFECT: { type: Scratch.ArgumentType.STRING, - menu: "enterEffectMenu", - defaultValue: "None", + menu: "effectMenu", + defaultValue: "Blur", + }, + AMT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, }, }, }, { - opcode: "setEnterSpeed", + opcode: "changeEffect", blockType: Scratch.BlockType.COMMAND, - text: "set enter effect speed to [SPEED]", + text: "change effect [EFFECT] by [AMT]", blockIconURI: effectIcon, arguments: { - SPEED: { + EFFECT: { type: Scratch.ArgumentType.STRING, - defaultValue: "10", + menu: "effectMenu", + defaultValue: "Blur", + }, + AMT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, }, }, }, { - opcode: "setExitEffect", - blockType: Scratch.BlockType.COMMAND, - text: "set exit effect to [EXIT_EFFECT]", + opcode: "showEffect", + blockType: Scratch.BlockType.REPORTER, + text: "effect [EFFECT]", blockIconURI: effectIcon, arguments: { - EXIT_EFFECT: { + EFFECT: { type: Scratch.ArgumentType.STRING, - menu: "exitEffectMenu", - defaultValue: "None", + menu: "effectMenu", + defaultValue: "Blur", }, }, }, { - opcode: "setExitSpeed", + opcode: "setTimeout", blockType: Scratch.BlockType.COMMAND, - text: "set exit effect speed to [SPEED]", + text: "when submitted delete textbox after [TIME] secs", blockIconURI: effectIcon, arguments: { - SPEED: { - type: Scratch.ArgumentType.STRING, - defaultValue: "10", + TIME: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, }, }, }, + { + opcode: "reportTimeout", + blockType: Scratch.BlockType.REPORTER, + text: "current textbox timeout", + blockIconURI: effectIcon, + }, { blockType: Scratch.BlockType.LABEL, text: "Operations", }, + { + opcode: "isWaitingInput", + blockType: Scratch.BlockType.BOOLEAN, + text: "is wating for Input?", + }, + { + opcode: "isDropdown", + blockType: Scratch.BlockType.BOOLEAN, + text: "is dropdown menu open?", + }, { opcode: "setSubmitEvent", blockType: Scratch.BlockType.COMMAND, @@ -455,66 +532,86 @@ }, ], menus: { - alignmentMenu: ["left", "right", "center"], - fontMenu: [ - "Arial", - "Times New Roman", - "Comic Sans MS", - "Verdana", - "Courier New", - "Impact", - "Cursive", - "Lucida Console", - "Scratch", - "Arial Black", - "Calibri", - "Consolas", - "Handwriting", - "Marker", - "Curly", - "Pixel", - "MS PGothic", - "Malgun Gothic", - "Microsoft YaHei", - ], - buttonActionMenu: ["Enabled", "Disabled"], - inputActionMenu: ["Enabled", "Disabled", "Dropdown", "Slider"], - enterEffectMenu: ["None", "Fade in", "Grow", "Both"], - exitEffectMenu: ["None", "Fade out", "Shrink", "Both"], - buttonMenu: [ - "Button 1", - "Button 2", - "Button 3", - "Button 4", - "Dropdown", - ], - enableMenu: ["Button 2", "Button 3", "Button 4"], - elementMenu: [ - "Textbox", - "Input Box", - "Button 1", - "Button 2", - "Button 3", - "Button 4", - "Dropdown Buttons", - ], - colorSettingsMenu: [ - "Question", - "Input Text", - "Textbox", - "Input Background", - "Input Outline", - "Button 1", - "Button 2", - "Button 3", - "Button 4", - "Dropdown Buttons", - "Button 1 Text", - "Button 2 Text", - "Button 3 Text", - "Button 4 Text", - "Dropdown Text", - ], + alignmentMenu: { + acceptReporters: true, + items: ["left", "right", "center"], + }, + fontMenu: { + acceptReporters: true, + items: [ + "Sans Serif", + "Serif", + "Handwriting", + "Marker", + "Curly", + "Pixel", + "Scratch", + ], + }, + buttonActionMenu: { + acceptReporters: true, + items: ["Enabled", "Disabled"], + }, + inputActionMenu: { + acceptReporters: true, + items: ["Enabled", "Disabled", "Dropdown", "Multi-Select Dropdown", "Slider"], + }, + effectMenu: { + acceptReporters: true, + items: [ + "Blur", + "Brightness", + "Opacity", + "Invert", + "Saturation", + "Hue", + "Sepia", + "Contrast", + "Scale", + "SkewX", + "SkewY", + ], + }, + buttonMenu: { + acceptReporters: true, + items: ["Button 1", "Button 2", "Button 3", "Button 4", "Dropdown"], + }, + enableMenu: { + acceptReporters: true, + items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"], + }, + elementMenu: { + acceptReporters: true, + items: [ + "Textbox", + "Input Box", + "Button 1", + "Button 2", + "Button 3", + "Button 4", + "Dropdown Buttons", + ], + }, + colorSettingsMenu: { + acceptReporters: true, + items: [ + "Question", + "Input Text", + "Textbox", + "Input Background", + "Input Outline", + "Button 1", + "Button 2", + "Button 3", + "Button 4", + "Dropdown Buttons", + "Button 1 Text", + "Button 2 Text", + "Button 3 Text", + "Button 4 Text", + "Dropdown Text", + ], + }, enterMenu: { acceptReporters: true, items: ["Disabled", "Enter Key", "Shift + Enter Key"], @@ -523,6 +620,75 @@ }; } + isWaitingInput(args) { + return this.isWaitingForInput; + } + + isDropdown(args) { + return this.isDropdownOpen; + } + + showEffect(args) { + const effect = args.EFFECT; + return this[effect]; + } + + setEffect(args) { + const effect = args.EFFECT; + this[effect] = args.AMT; + + this.activeOverlays.forEach((overlay) => { + this.updateEffect(overlay); + }); + } + + changeEffect(args) { + const effect = args.EFFECT; + this[effect] = this[effect] + args.AMT; + + this.activeOverlays.forEach((overlay) => { + this.updateEffect(overlay); + }); + } + + resetEffect(args) { + this.Blur = 0; + this.Brightness = 100; + this.Opacity = 100; + this.Invert = 0; + this.Saturation = 100; + this.Hue = 0; + this.Sepia = 0; + this.Contrast = 100; + this.Scale = 100; + this.SkewX = 0; + this.SkewY = 0; + + this.activeOverlays.forEach((overlay) => { + this.updateEffect(overlay); + }); + } + + updateEffect(overlay) { + const newOpacity = this.Opacity / 100; + const newScale = this.Scale / 100; + overlay.style.filter = ` + blur(${this.Blur}px) + brightness(${this.Brightness}%) + invert(${this.Invert}%) + saturate(${this.Saturation}%) + hue-rotate(${this.Hue}deg) + sepia(${this.Sepia}%) + contrast(${this.Contrast}%) + `; + overlay.style.opacity = newOpacity; + overlay.style.scale = newScale; + overlay.style.transform = ` + SkewX(${this.SkewX}deg) + SkewY(${this.SkewY}deg) + `; + } + setColorSettings(args) { const colorType = args.COLOR_TYPE; const colorValue = args.COLOR; @@ -616,68 +782,62 @@ } } - setEnterEffect(args) { - const enterEffect = args.ENTER_EFFECT; - switch (enterEffect) { - case "None": - this.enterEffect = null; - break; - case "Fade in": - this.enterEffect = "fadeIn"; - break; - case "Grow": - this.enterEffect = "growIn"; - break; - case "Both": - this.enterEffect = "Both"; - break; - } - } + setDirection(args) { + const ROTATE = args.ROTATE; + this.Rotation = Scratch.Cast.toNumber(ROTATE); - setExitEffect(args) { - const exitEffect = args.EXIT_EFFECT; - switch (exitEffect) { - case "None": - this.exitEffect = null; - break; - case "Fade out": - this.exitEffect = "fadeOut"; - break; - case "Shrink": - this.exitEffect = "shrinkOut"; - break; - case "Both": - this.exitEffect = "Both"; - break; - } + this.activeOverlays.forEach((overlay) => { + this.updateOverlayPosition(overlay); + }); } + + changeDirection(args) { + const ROTATE = args.ROTATE; + this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); + this.activeOverlays.forEach((overlay) => { + this.updateOverlayPosition(overlay); + }); + } + + reportDirection(args) { + return this.Rotation; + } + setPrePosition(args) { - this.textBoxX = args.X; - this.textBoxY = args.Y * -1; + this.textBoxX = Scratch.Cast.toNumber(args.X); + this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; } setPosition(args) { - this.textBoxX = args.X; - this.textBoxY = args.Y * -1; + this.textBoxX = Scratch.Cast.toNumber(args.X); + this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; - const overlays = document.querySelectorAll(".ask-box"); - overlays.forEach((overlay) => { + this.activeOverlays.forEach((overlay) => { this.updateOverlayPosition(overlay); }); } changePosition(args) { - this.textBoxX = this.textBoxX + args.X; - this.textBoxY = this.textBoxY + args.Y * -1; + this.textBoxX = this.textBoxX + Scratch.Cast.toNumber(args.X); + this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) * -1; - const overlays = document.querySelectorAll(".ask-box"); - overlays.forEach((overlay) => { + this.activeOverlays.forEach((overlay) => { this.updateOverlayPosition(overlay); }); } updateOverlayPosition(overlay) { + if (this.Rotation > 359) { + this.Rotation = 0; + } else if (this.Rotation < 1) { + this.Rotation = 360; + } + overlay.style.transform = ` + SkewX(${this.SkewX}deg) + SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) + `; if (this.textBoxX !== null && this.textBoxY !== null) { overlay.style.left = `${41 + this.textBoxX}%`; overlay.style.top = `${44 + this.textBoxY}%`; @@ -702,6 +862,15 @@ setFontFamily(args) { this.fontFamily = args.FONT; } + + setTimeout(args) { + this.Timeout = args.TIME; + this.Condition = args.CONDITION; + } + + reportTimeout(args) { + return this.Timeout; + } setSlider(args) { this.minSlider = args.MIN; @@ -722,6 +891,9 @@ case "Button 4": this.showButton4 = action === "Enabled"; break; + case "Textbox Shadow": + this.shadowEnabled = action === "Enabled"; + break; } } @@ -775,106 +947,6 @@ this.userInput = ""; } - applyEnterEffect(overlay) { - overlay.style.opacity = "1"; - overlay.style.transform = "scale(1)"; - - let currentOpacity = 0; - let currentScale = 0; - - if (this.enterEffect !== "None") { - if (this.enterEffect === "fadeIn" || this.enterEffect === "Both") { - overlay.style.opacity = "0"; - } - - if (this.enterEffect === "growIn" || this.enterEffect === "Both") { - overlay.style.transform = "scale(0)"; - overlay.style.transition = "opacity 0.3s"; - } - - const step = () => { - if ( - (this.enterEffect === "fadeIn" || this.enterEffect === "Both") && - currentOpacity < 100 - ) { - currentOpacity += this.enterSpeed; - overlay.style.opacity = `${currentOpacity}%`; - } - - if ( - (this.enterEffect === "growIn" || this.enterEffect === "Both") && - currentScale < 100 - ) { - currentScale += this.enterSpeed; - overlay.style.transform = `scale(${currentScale / 100})`; - } - - if ( - (this.enterEffect === "Both" && - (currentOpacity < 100 || currentScale < 100)) || - (this.enterEffect === "growIn" && currentScale < 100) || - (this.enterEffect !== "Both" && currentOpacity < 100) - ) { - requestAnimationFrame(step); - } - }; - - if (this.enterEffect === "growIn" || this.enterEffect === "Both") { - overlay.style.transition = "opacity 0.3s"; - } - - requestAnimationFrame(step); - } else { - overlay.style.opacity = "1"; - } - } - - applyExitEffect(overlay) { - let currentScale = 100; - let currentOpacity = 0; - - if (this.exitEffect !== "None") { - if (this.exitEffect === "fadeOut") { - overlay.style.transition = "opacity 0.5s"; - } else { - overlay.style.transition = "transform 0.5s, opacity 0.5s"; - } - - const step = () => { - if ( - (this.exitEffect === "fadeOut" || this.exitEffect === "Both") && - currentOpacity < 100 - ) { - currentOpacity -= this.exitSpeed; - overlay.style.opacity = `${currentOpacity}%`; - } - - if ( - (this.exitEffect === "shrinkOut" || this.exitEffect === "Both") && - currentScale > 0 - ) { - currentScale -= this.exitSpeed; - overlay.style.transform = `scale(${currentScale / 100})`; - } - - if ( - (this.exitEffect === "Both" && - (currentOpacity > -200 || currentScale > -100)) || - (this.exitEffect === "shrinkOut" && currentScale > -100) || - (this.exitEffect !== "Both" && currentOpacity > -200) - ) { - requestAnimationFrame(step); - } else { - document.body.removeChild(overlay); - } - }; - - requestAnimationFrame(step); - } else { - document.body.removeChild(overlay); - } - } - askAndWait(args) { if (this.askBoxCount < this.maxBoxCount) { const question = args.question; @@ -890,21 +962,25 @@ return new Promise((resolve) => { this.askBoxPromise.resolve = resolve; const overlay = document.createElement("div"); + this.activeOverlays.push(overlay); overlay.classList.add("ask-box"); overlay.style.position = "fixed"; overlay.style.left = `${41 + this.textBoxX}%`; overlay.style.top = `${44 + this.textBoxY}%`; overlay.style.zIndex = "9999"; overlay.style.backgroundColor = this.textBoxColor; - overlay.style.boxShadow = "0 0 5px rgba(0, 0, 0, 0.3)"; + overlay.style.boxShadow = this.shadowEnabled ? "0 0 5px rgba(0, 0, 0, 0.3)" : "none"; overlay.style.borderRadius = this.textBoxBorderRadius + "px"; overlay.style.padding = "15px"; overlay.style.fontSize = this.fontSize; overlay.style.textAlign = this.textAlign; overlay.style.fontFamily = this.fontFamily; + this.updateEffect(overlay); const overlayImageContainer = document.createElement("div"); - overlayImageContainer.style.background = `url(${this.overlayImage})`; + overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; + + //maybe in a future update we can make these customizable too... overlayImageContainer.style.width = "100%"; overlayImageContainer.style.height = "100%"; overlayImageContainer.style.position = "absolute"; @@ -931,14 +1007,8 @@ event.key === overlayInput ) { this.userInput = inputField.value; - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } + this.closeOverlay(overlay); resolve(); - this.askBoxCount--; } }; @@ -986,7 +1056,7 @@ submitButton.style.color = this.submitButtonTextColor; submitButton.style.border = "none"; submitButton.style.borderRadius = - this.submitButtonBorderRadius + "px"; + this.submitButtonBorderRadius + "px"; submitButton.style.cursor = "pointer"; submitButton.textContent = this.submitButtonText; @@ -996,14 +1066,8 @@ } else { this.userInput = this.submitButtonText; } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } + this.closeOverlay(overlay); resolve(); - this.askBoxCount--; }); const cancelButton = document.createElement("button"); @@ -1014,7 +1078,7 @@ cancelButton.style.color = this.cancelButtonTextColor; cancelButton.style.border = "none"; cancelButton.style.borderRadius = - this.cancelButtonBorderRadius + "px"; + this.cancelButtonBorderRadius + "px"; cancelButton.style.cursor = "pointer"; cancelButton.textContent = this.cancelButtonText; cancelButton.style.display = this.showCancelButton @@ -1027,14 +1091,8 @@ } else { this.userInput = ""; } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } + this.closeOverlay(overlay); resolve(); - this.askBoxCount--; }); const Button3 = document.createElement("button"); @@ -1055,14 +1113,8 @@ } else { this.userInput = ""; } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } + this.closeOverlay(overlay); resolve(); - this.askBoxCount--; }); const Button4 = document.createElement("button"); @@ -1083,14 +1135,8 @@ } else { this.userInput = ""; } - this.isWaitingForInput = false; - if (this.exitEffect) { - this.applyExitEffect(overlay); - } else { - document.body.removeChild(overlay); - } + this.closeOverlay(overlay); resolve(); - this.askBoxCount--; }); const dropdown = document.createElement("div"); @@ -1104,16 +1150,16 @@ dropdownButton.style.color = this.optionbuttonTextColor; dropdownButton.style.border = "none"; dropdownButton.style.borderRadius = - this.optionbuttonBorderRadius + "px"; + this.optionbuttonBorderRadius + "px"; const dropdownContent = document.createElement("div"); dropdownContent.className = "dropdown-content"; - - let isDropdownOpen = false; + this.isDropdownOpen = false; const optionList = this.optionList; const numOfOptions = optionList.split(this.splitKey).length; const options = this.optionList.split(this.splitKey); + const listing = Math.floor((optionList.length/2) / numOfOptions) -1; for (let i = 1; i <= numOfOptions; i++) { const optionButton = document.createElement("button"); optionButton.style.marginRight = "5px"; @@ -1123,34 +1169,54 @@ optionButton.style.color = this.optionbuttonTextColor; optionButton.style.border = "none"; optionButton.style.borderRadius = - this.optionbuttonBorderRadius + "px"; + this.optionbuttonBorderRadius + "px"; optionButton.textContent = `${options[i - 1]}`; optionButton.style.filter = "brightness(1)"; optionButton.addEventListener("click", () => { - inputField.value = `${options[i - 1]}`; - - for (let j = 0; j < numOfOptions; j++) { - const otherButton = dropdownContent.children[j]; - otherButton.style.filter = "brightness(1)"; + if (this.isInputEnabled === "Multi-Select Dropdown") { + const selectedOptions = inputField.value.split(this.splitKey); + const isSelected = selectedOptions.includes(options[i - 1]); + + if (isSelected) { + inputField.value = selectedOptions.filter(option => option !== options[i - 1]).join(this.splitKey); + } else { + inputField.value = [...selectedOptions, options[i - 1]].join(this.splitKey); + } + + const newSelectedOptions = inputField.value.split(this.splitKey); + + for (let j = 0; j < numOfOptions; j++) { + const otherButton = dropdownContent.children[j]; + otherButton.style.filter = newSelectedOptions.includes(options[j]) ? "brightness(1.5)" : "brightness(1)"; + } + } else { + inputField.value = `${options[i - 1]}`; + + for (let j = 0; j < numOfOptions; j++) { + const otherButton = dropdownContent.children[j]; + otherButton.style.filter = otherButton === optionButton ? "brightness(1.5)" : "brightness(1)"; + } } - - optionButton.style.filter = "brightness(1.5)"; }); dropdownContent.appendChild(optionButton); + if (i % listing === 0 && i !== numOfOptions) { + const lineBreak = document.createElement("br"); + dropdownContent.appendChild(lineBreak); + } } dropdownButton.addEventListener("mouseover", () => { - if (!isDropdownOpen) { + if (!this.isDropdownOpen) { overlay.insertBefore(dropdownContent, submitButton); - isDropdownOpen = true; + this.isDropdownOpen = true; } }); overlay.addEventListener("mouseleave", () => { - if (isDropdownOpen) { + if (this.isDropdownOpen) { overlay.removeChild(dropdownContent); - isDropdownOpen = false; + this.isDropdownOpen = false; } }); @@ -1181,7 +1247,7 @@ if (this.isInputEnabled !== "Disabled") { if (this.isInputEnabled === "Enabled") { overlay.appendChild(inputField); - } else if (this.isInputEnabled === "Dropdown") { + } else if (this.isInputEnabled === "Dropdown" || this.isInputEnabled === "Multi-Select Dropdown") { dropdown.appendChild(dropdownButton); overlay.appendChild(dropdown); } else { @@ -1299,6 +1365,24 @@ setImage(args) { this.overlayImage = args.IMAGE; } + + removeOverlay(overlay) { + const index = this.activeOverlays.indexOf(overlay); + if (index !== -1) { + this.activeOverlays.splice(index, 1); + } + document.body.removeChild(overlay); + } + + closeOverlay(overlay) { + this.isWaitingForInput = false; + this.isDropdownOpen = false; + this.askBoxCount--; + const timeout = this.Timeout * 1000; + setTimeout(() => { + document.body.removeChild(overlay); + }, timeout); + } } Scratch.extensions.register(new BetterInputSP()); From abadd6e7caad989bf0a512d74b1084d4767e5527 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 19 Aug 2023 00:20:51 -0700 Subject: [PATCH 10/46] Update BetterInput.js shut up eslint --- extensions/SharkPool/BetterInput.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index f67efe98b7..194176f05c 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,7 +1,7 @@ /* * This extension was made by SharkPool * Version 2.1 (Fixes, Booleans, More Customization, Rotation, More Effects, and Performance Updates) - * Next Update: Image Setting Additions + * Next Update: Redo Effects Tab (again but cooler) & Image Setting Additions * Do NOT delete these comments */ @@ -217,7 +217,7 @@ FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu", - defaultValue: "Arial", + defaultValue: "Sans Serif", }, }, }, @@ -627,7 +627,7 @@ isDropdown(args) { return this.isDropdownOpen; } - + showEffect(args) { const effect = args.EFFECT; return this[effect]; @@ -636,7 +636,7 @@ setEffect(args) { const effect = args.EFFECT; this[effect] = args.AMT; - + this.activeOverlays.forEach((overlay) => { this.updateEffect(overlay); }); @@ -1159,7 +1159,7 @@ const optionList = this.optionList; const numOfOptions = optionList.split(this.splitKey).length; const options = this.optionList.split(this.splitKey); - const listing = Math.floor((optionList.length/2) / numOfOptions) -1; + const listing = Math.floor((optionList.length / 2) / numOfOptions) - 1; for (let i = 1; i <= numOfOptions; i++) { const optionButton = document.createElement("button"); optionButton.style.marginRight = "5px"; From 5a1aa155ebef75ad5ea888b6b258025413221b31 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 19 Aug 2023 00:25:36 -0700 Subject: [PATCH 11/46] Update BetterInput.js shut it eslint :( --- extensions/SharkPool/BetterInput.js | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 194176f05c..6904811d54 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -623,7 +623,7 @@ isWaitingInput(args) { return this.isWaitingForInput; } - + isDropdown(args) { return this.isDropdownOpen; } @@ -641,7 +641,7 @@ this.updateEffect(overlay); }); } - + changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; @@ -650,7 +650,7 @@ this.updateEffect(overlay); }); } - + resetEffect(args) { this.Blur = 0; this.Brightness = 100; @@ -663,7 +663,7 @@ this.Scale = 100; this.SkewX = 0; this.SkewY = 0; - + this.activeOverlays.forEach((overlay) => { this.updateEffect(overlay); }); @@ -688,7 +688,7 @@ SkewY(${this.SkewY}deg) `; } - + setColorSettings(args) { const colorType = args.COLOR_TYPE; const colorValue = args.COLOR; @@ -790,7 +790,7 @@ this.updateOverlayPosition(overlay); }); } - + changeDirection(args) { const ROTATE = args.ROTATE; this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); @@ -799,11 +799,11 @@ this.updateOverlayPosition(overlay); }); } - + reportDirection(args) { return this.Rotation; } - + setPrePosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X); this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; @@ -862,12 +862,12 @@ setFontFamily(args) { this.fontFamily = args.FONT; } - + setTimeout(args) { this.Timeout = args.TIME; this.Condition = args.CONDITION; } - + reportTimeout(args) { return this.Timeout; } @@ -979,7 +979,7 @@ const overlayImageContainer = document.createElement("div"); overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; - + //maybe in a future update we can make these customizable too... overlayImageContainer.style.width = "100%"; overlayImageContainer.style.height = "100%"; @@ -1177,22 +1177,21 @@ if (this.isInputEnabled === "Multi-Select Dropdown") { const selectedOptions = inputField.value.split(this.splitKey); const isSelected = selectedOptions.includes(options[i - 1]); - + if (isSelected) { inputField.value = selectedOptions.filter(option => option !== options[i - 1]).join(this.splitKey); } else { inputField.value = [...selectedOptions, options[i - 1]].join(this.splitKey); } - + const newSelectedOptions = inputField.value.split(this.splitKey); - for (let j = 0; j < numOfOptions; j++) { const otherButton = dropdownContent.children[j]; otherButton.style.filter = newSelectedOptions.includes(options[j]) ? "brightness(1.5)" : "brightness(1)"; } } else { inputField.value = `${options[i - 1]}`; - + for (let j = 0; j < numOfOptions; j++) { const otherButton = dropdownContent.children[j]; otherButton.style.filter = otherButton === optionButton ? "brightness(1.5)" : "brightness(1)"; @@ -1365,7 +1364,7 @@ setImage(args) { this.overlayImage = args.IMAGE; } - + removeOverlay(overlay) { const index = this.activeOverlays.indexOf(overlay); if (index !== -1) { @@ -1373,7 +1372,7 @@ } document.body.removeChild(overlay); } - + closeOverlay(overlay) { this.isWaitingForInput = false; this.isDropdownOpen = false; From 1c691121d7317a11a854369d45c7e62ec03852b9 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 19 Aug 2023 00:27:33 -0700 Subject: [PATCH 12/46] Update BetterInput.js ESLINT LEAVE ME ALONE --- extensions/SharkPool/BetterInput.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 6904811d54..8de63e5895 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -632,7 +632,7 @@ const effect = args.EFFECT; return this[effect]; } - + setEffect(args) { const effect = args.EFFECT; this[effect] = args.AMT; @@ -645,7 +645,7 @@ changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; - + this.activeOverlays.forEach((overlay) => { this.updateEffect(overlay); }); From 808958eb91cf55b2fe2c1084593885663b5b1553 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 19 Aug 2023 00:28:50 -0700 Subject: [PATCH 13/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 8de63e5895..4eaceaec19 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,7 +1,7 @@ /* * This extension was made by SharkPool * Version 2.1 (Fixes, Booleans, More Customization, Rotation, More Effects, and Performance Updates) - * Next Update: Redo Effects Tab (again but cooler) & Image Setting Additions + * Next Update: Image Setting Additions * Do NOT delete these comments */ From 559851ebe09d3855f14e29422d69e1a6f53bbbfd Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:45:06 -0700 Subject: [PATCH 14/46] Update BetterInput.js Small Fixes --- extensions/SharkPool/BetterInput.js | 134 +++++++++++++++------------- 1 file changed, 73 insertions(+), 61 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 4eaceaec19..eb57477400 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,6 +1,6 @@ /* * This extension was made by SharkPool - * Version 2.1 (Fixes, Booleans, More Customization, Rotation, More Effects, and Performance Updates) + * Version 2.1.1 (Fixes, Booleans, More Customization, Rotation, More Effects, and Performance Updates) * Next Update: Image Setting Additions * Do NOT delete these comments */ @@ -31,7 +31,7 @@ constructor() { this.isWaitingForInput = false; this.isDropdownOpen = false; - this.userInput = ""; + this.userInput = " "; this.fontSize = "14px"; this.questionColor = "#000000"; this.inputColor = "#000000"; @@ -39,7 +39,7 @@ this.inputBackgroundColor = "#ffffff"; this.inputOutlineColor = "#000000"; this.textAlign = "left"; - this.fontFamily = "Arial"; + this.fontFamily = "Sans Serif"; this.showCancelButton = true; this.showButton3 = false; this.showButton4 = false; @@ -83,7 +83,7 @@ this.exitSpeed = 10; this.activeOverlays = []; this.Blur = 0; - this.Brightness = 100; + this.Brightness = 0; this.Opacity = 100; this.Invert = 0; this.Saturation = 100; @@ -95,6 +95,7 @@ this.SkewY = 0; this.Rotation = 90; this.Timeout = 0; + this.imageSettings = ['100%', '100%']; } getInfo() { @@ -539,13 +540,13 @@ fontMenu: { acceptReporters: true, items: [ + "Scratch", "Sans Serif", "Serif", "Handwriting", "Marker", "Curly", - "Pixel", - "Scratch", + "Pixel" ], }, buttonActionMenu: { @@ -623,7 +624,7 @@ isWaitingInput(args) { return this.isWaitingForInput; } - + isDropdown(args) { return this.isDropdownOpen; } @@ -632,28 +633,28 @@ const effect = args.EFFECT; return this[effect]; } - + setEffect(args) { const effect = args.EFFECT; this[effect] = args.AMT; this.activeOverlays.forEach((overlay) => { - this.updateEffect(overlay); + this.updateOverlay(overlay); }); } - + changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; - + this.activeOverlays.forEach((overlay) => { - this.updateEffect(overlay); + this.updateOverlay(overlay); }); } - + resetEffect(args) { this.Blur = 0; - this.Brightness = 100; + this.Brightness = 0; this.Opacity = 100; this.Invert = 0; this.Saturation = 100; @@ -663,32 +664,12 @@ this.Scale = 100; this.SkewX = 0; this.SkewY = 0; - + this.activeOverlays.forEach((overlay) => { - this.updateEffect(overlay); + this.updateOverlay(overlay); }); } - updateEffect(overlay) { - const newOpacity = this.Opacity / 100; - const newScale = this.Scale / 100; - overlay.style.filter = ` - blur(${this.Blur}px) - brightness(${this.Brightness}%) - invert(${this.Invert}%) - saturate(${this.Saturation}%) - hue-rotate(${this.Hue}deg) - sepia(${this.Sepia}%) - contrast(${this.Contrast}%) - `; - overlay.style.opacity = newOpacity; - overlay.style.scale = newScale; - overlay.style.transform = ` - SkewX(${this.SkewX}deg) - SkewY(${this.SkewY}deg) - `; - } - setColorSettings(args) { const colorType = args.COLOR_TYPE; const colorValue = args.COLOR; @@ -759,10 +740,10 @@ this.textBoxBorderRadius = value; break; case "Button 1": - this.cancelButtonBorderRadius = value; + this.submitButtonBorderRadius = value; break; case "Button 2": - this.submitButtonBorderRadius = value; + this.cancelButtonBorderRadius = value; break; case "Button 3": this.button3BorderRadius = value; @@ -787,23 +768,23 @@ this.Rotation = Scratch.Cast.toNumber(ROTATE); this.activeOverlays.forEach((overlay) => { - this.updateOverlayPosition(overlay); + this.updateOverlay(overlay); }); } - + changeDirection(args) { const ROTATE = args.ROTATE; this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); this.activeOverlays.forEach((overlay) => { - this.updateOverlayPosition(overlay); + this.updateOverlay(overlay); }); } - + reportDirection(args) { return this.Rotation; } - + setPrePosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X); this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; @@ -814,7 +795,7 @@ this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; this.activeOverlays.forEach((overlay) => { - this.updateOverlayPosition(overlay); + this.updateOverlay(overlay); }); } @@ -823,21 +804,38 @@ this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) * -1; this.activeOverlays.forEach((overlay) => { - this.updateOverlayPosition(overlay); + this.updateOverlay(overlay); }); } - updateOverlayPosition(overlay) { + updateOverlay(overlay) { if (this.Rotation > 359) { this.Rotation = 0; } else if (this.Rotation < 1) { this.Rotation = 360; } + + const newOpacity = this.Opacity / 100; + const newScale = this.Scale / 100; + const newBrightness = this.Brightness + 100; + overlay.style.transform = ` SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) rotate(${this.Rotation - 90}deg) `; + overlay.style.filter = ` + blur(${this.Blur}px) + brightness(${newBrightness}%) + invert(${this.Invert}%) + saturate(${this.Saturation}%) + hue-rotate(${this.Hue}deg) + sepia(${this.Sepia}%) + contrast(${this.Contrast}%) + `; + overlay.style.opacity = newOpacity; + overlay.style.scale = newScale; + if (this.textBoxX !== null && this.textBoxY !== null) { overlay.style.left = `${41 + this.textBoxX}%`; overlay.style.top = `${44 + this.textBoxY}%`; @@ -862,12 +860,12 @@ setFontFamily(args) { this.fontFamily = args.FONT; } - + setTimeout(args) { this.Timeout = args.TIME; this.Condition = args.CONDITION; } - + reportTimeout(args) { return this.Timeout; } @@ -975,17 +973,16 @@ overlay.style.fontSize = this.fontSize; overlay.style.textAlign = this.textAlign; overlay.style.fontFamily = this.fontFamily; - this.updateEffect(overlay); const overlayImageContainer = document.createElement("div"); overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; - //maybe in a future update we can make these customizable too... - overlayImageContainer.style.width = "100%"; - overlayImageContainer.style.height = "100%"; + overlayImageContainer.style.width = '100%'; + overlayImageContainer.style.height = '100%'; overlayImageContainer.style.position = "absolute"; - overlayImageContainer.style.top = "0"; - overlayImageContainer.style.left = "0"; + overlayImageContainer.style.top = 0; + overlayImageContainer.style.left = 0; + overlayImageContainer.style.borderRadius = this.textBoxBorderRadius + "px"; overlayImageContainer.style.zIndex = "-1"; if (this.forceInput !== "Disabled") { @@ -1006,7 +1003,13 @@ event.key === "Enter") || event.key === overlayInput ) { - this.userInput = inputField.value; + if (this.isInputEnabled === "Multi-Select Dropdown") { + inputField.value = inputField.value.substring(1); + inputField.value = inputField.value.replace(this.splitKey, '", "'); + this.userInput = '["' + inputField.value + '"]'; + } else { + this.userInput = inputField.value; + } this.closeOverlay(overlay); resolve(); } @@ -1062,7 +1065,13 @@ submitButton.addEventListener("click", () => { if (this.isInputEnabled !== "Disabled") { - this.userInput = inputField.value; + if (this.isInputEnabled === "Multi-Select Dropdown") { + inputField.value = inputField.value.substring(1); + inputField.value = inputField.value.replace(this.splitKey, '", "'); + this.userInput = '["' + inputField.value + '"]'; + } else { + this.userInput = inputField.value; + } } else { this.userInput = this.submitButtonText; } @@ -1081,9 +1090,7 @@ this.cancelButtonBorderRadius + "px"; cancelButton.style.cursor = "pointer"; cancelButton.textContent = this.cancelButtonText; - cancelButton.style.display = this.showCancelButton - ? "inline-block" - : "none"; + cancelButton.style.display = this.showCancelButton ? "inline-block" : "none"; cancelButton.addEventListener("click", () => { if (this.isInputEnabled === "Disabled") { @@ -1177,7 +1184,7 @@ if (this.isInputEnabled === "Multi-Select Dropdown") { const selectedOptions = inputField.value.split(this.splitKey); const isSelected = selectedOptions.includes(options[i - 1]); - + if (isSelected) { inputField.value = selectedOptions.filter(option => option !== options[i - 1]).join(this.splitKey); } else { @@ -1287,6 +1294,11 @@ document.addEventListener("mozfullscreenchange", resizeHandler); document.addEventListener("MSFullscreenChange", resizeHandler); + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + overlay.style.transform = `rotate(${this.Rotation - 90}deg)`; + }); + const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if ( @@ -1372,7 +1384,7 @@ } document.body.removeChild(overlay); } - + closeOverlay(overlay) { this.isWaitingForInput = false; this.isDropdownOpen = false; From ed53b8d6d4402ffcca2db2b8a3f8499c294dd7c8 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:48:37 -0700 Subject: [PATCH 15/46] Update BetterInput.js Eslint is bullying me :( --- extensions/SharkPool/BetterInput.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index eb57477400..d8b4b34aee 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -624,7 +624,7 @@ isWaitingInput(args) { return this.isWaitingForInput; } - + isDropdown(args) { return this.isDropdownOpen; } @@ -633,7 +633,7 @@ const effect = args.EFFECT; return this[effect]; } - + setEffect(args) { const effect = args.EFFECT; this[effect] = args.AMT; @@ -642,16 +642,16 @@ this.updateOverlay(overlay); }); } - + changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; - + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); }); } - + resetEffect(args) { this.Blur = 0; this.Brightness = 0; @@ -664,7 +664,7 @@ this.Scale = 100; this.SkewX = 0; this.SkewY = 0; - + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); }); @@ -771,7 +771,7 @@ this.updateOverlay(overlay); }); } - + changeDirection(args) { const ROTATE = args.ROTATE; this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); @@ -780,11 +780,11 @@ this.updateOverlay(overlay); }); } - + reportDirection(args) { return this.Rotation; } - + setPrePosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X); this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; @@ -860,12 +860,12 @@ setFontFamily(args) { this.fontFamily = args.FONT; } - + setTimeout(args) { this.Timeout = args.TIME; this.Condition = args.CONDITION; } - + reportTimeout(args) { return this.Timeout; } @@ -1184,7 +1184,7 @@ if (this.isInputEnabled === "Multi-Select Dropdown") { const selectedOptions = inputField.value.split(this.splitKey); const isSelected = selectedOptions.includes(options[i - 1]); - + if (isSelected) { inputField.value = selectedOptions.filter(option => option !== options[i - 1]).join(this.splitKey); } else { @@ -1384,7 +1384,7 @@ } document.body.removeChild(overlay); } - + closeOverlay(overlay) { this.isWaitingForInput = false; this.isDropdownOpen = false; From 1213f9281aeb4fb9fd17c86383945c696faa21d0 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:13:54 -0700 Subject: [PATCH 16/46] Final Changes --- extensions/SharkPool/BetterInput.js | 204 +++++++++++++++++++++++++--- 1 file changed, 187 insertions(+), 17 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index d8b4b34aee..ee77920d51 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,7 +1,6 @@ /* * This extension was made by SharkPool - * Version 2.1.1 (Fixes, Booleans, More Customization, Rotation, More Effects, and Performance Updates) - * Next Update: Image Setting Additions + * Version 2.2 (Visual Effects Expansion + Fixes) * Do NOT delete these comments */ @@ -27,6 +26,9 @@ const effectIcon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + let newColorType = ''; + let overlayImageContainer = ''; + class BetterInputSP { constructor() { this.isWaitingForInput = false; @@ -95,7 +97,8 @@ this.SkewY = 0; this.Rotation = 90; this.Timeout = 0; - this.imageSettings = ['100%', '100%']; + this.imgScale = 100; + this.shadowS = ['0','0','5','0.3']; } getInfo() { @@ -380,6 +383,80 @@ }, }, }, + { + opcode: "setShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set shadow [SHADOW] to [AMT]", + blockIconURI: colorIcon, + arguments: { + SHADOW: { + type: Scratch.ArgumentType.STRING, + menu: "shadowStuff", + defaultValue: "Scale", + }, + AMT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: "5", + }, + }, + }, + { + opcode: "setGradient", + blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to gradient with colors [COLOR1] and [COLOR2] with direction [DIR]", + blockIconURI: colorIcon, + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, + COLOR1: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#ffffff", + }, + COLOR2: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#ff0000", + }, + DIR: { + type: Scratch.ArgumentType.ANGLE, + defaultValue: 90, + }, + }, + }, + { + opcode: "setCircleGradient", + blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to radial gradient with colors [COLOR1] and [COLOR2] with position x [X] y [Y]", + blockIconURI: colorIcon, + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, + COLOR1: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#ffffff", + }, + COLOR2: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#ff0000", + }, + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + }, + }, + + '---', + { opcode: "setBorderRadius", blockType: Scratch.BlockType.COMMAND, @@ -397,6 +474,9 @@ }, }, }, + + '---', + { opcode: "setImage", blockType: Scratch.BlockType.COMMAND, @@ -409,6 +489,18 @@ }, }, }, + { + opcode: "scaleImage", + blockType: Scratch.BlockType.COMMAND, + text: "scale background image to [SCALE]%", + blockIconURI: colorIcon, + arguments: { + SCALE: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 100, + }, + }, + }, { blockType: Scratch.BlockType.LABEL, text: "Effects", @@ -573,6 +665,10 @@ "SkewY", ], }, + shadowStuff: { + acceptReporters: true, + items: ["Scale", "X", "Y", "Opacity"], + }, buttonMenu: { acceptReporters: true, items: ["Button 1", "Button 2", "Button 3", "Button 4", "Dropdown"], @@ -727,6 +823,51 @@ } } + findGradientType(menu) { + const colorType = menu; + + switch (colorType) { + case "Textbox": + newColorType = 'textBoxColor'; + this.overlayImage = null; + break; + case "Input Box": + newColorType = 'inputBackgroundColor'; + break; + case "Button 1": + newColorType = 'submitButtonColor'; + break; + case "Button 2": + newColorType = 'cancelButtonColor'; + break; + case "Button 3": + newColorType = 'button3Color'; + break; + case "Button 4": + newColorType = 'button4Color'; + break; + case "Dropdown Buttons": + newColorType = 'optionbuttonColor'; + break; + } + return newColorType; + } + + setGradient(args) { + this.findGradientType(args.COLOR_TYPE); + const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; + this[newColorType] = gradientColor; + } + + setCircleGradient(args) { + this.findGradientType(args.COLOR_TYPE); + const newX = args.X + 50; + const newY = args.Y + 50; + + const gradientColor = `radial-gradient(circle at ${newX}% ${newY}%, ${args.COLOR2}, ${args.COLOR1})`; + this[newColorType] = gradientColor; + } + setBorderRadius(args) { const element = args.ELEMENT; let value = args.VALUE; @@ -836,6 +977,9 @@ overlay.style.opacity = newOpacity; overlay.style.scale = newScale; + overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; + overlayImageContainer.style.backgroundSize = this.imgScale + '%'; + if (this.textBoxX !== null && this.textBoxY !== null) { overlay.style.left = `${41 + this.textBoxX}%`; overlay.style.top = `${44 + this.textBoxY}%`; @@ -966,17 +1110,17 @@ overlay.style.left = `${41 + this.textBoxX}%`; overlay.style.top = `${44 + this.textBoxY}%`; overlay.style.zIndex = "9999"; - overlay.style.backgroundColor = this.textBoxColor; - overlay.style.boxShadow = this.shadowEnabled ? "0 0 5px rgba(0, 0, 0, 0.3)" : "none"; + overlay.style[this.textBoxColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.textBoxColor; + overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px rgba(0, 0, 0, ${this.shadowS[3]})` : "none"; overlay.style.borderRadius = this.textBoxBorderRadius + "px"; overlay.style.padding = "15px"; overlay.style.fontSize = this.fontSize; overlay.style.textAlign = this.textAlign; overlay.style.fontFamily = this.fontFamily; - const overlayImageContainer = document.createElement("div"); + overlayImageContainer = document.createElement("div"); overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; - + overlayImageContainer.style.backgroundSize = this.imgScale + '%'; overlayImageContainer.style.width = '100%'; overlayImageContainer.style.height = '100%'; overlayImageContainer.style.position = "absolute"; @@ -1028,7 +1172,6 @@ }); observer.observe(document.body, { childList: true }); - document.addEventListener("keydown", handleKeydown); } @@ -1045,7 +1188,7 @@ inputField.style.padding = "5px"; inputField.style.fontSize = this.fontSize; inputField.style.color = this.inputColor; - inputField.style.backgroundColor = this.inputBackgroundColor; + inputField.style[this.inputBackgroundColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.inputBackgroundColor; inputField.style.border = `1px solid ${this.inputOutlineColor}`; inputField.style.borderRadius = this.inputBoxRadius + "px"; inputField.style.margin = "0 auto"; @@ -1055,7 +1198,7 @@ submitButton.style.marginTop = "10px"; submitButton.style.marginRight = "5px"; submitButton.style.padding = "5px 10px"; - submitButton.style.backgroundColor = this.submitButtonColor; + submitButton.style[this.submitButtonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.submitButtonColor; submitButton.style.color = this.submitButtonTextColor; submitButton.style.border = "none"; submitButton.style.borderRadius = @@ -1083,7 +1226,7 @@ cancelButton.style.marginTop = "10px"; cancelButton.style.marginRight = "5px"; cancelButton.style.padding = "5px 10px"; - cancelButton.style.backgroundColor = this.cancelButtonColor; + cancelButton.style[this.cancelButtonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.cancelButtonColor; cancelButton.style.color = this.cancelButtonTextColor; cancelButton.style.border = "none"; cancelButton.style.borderRadius = @@ -1106,7 +1249,7 @@ Button3.style.marginTop = "10px"; Button3.style.marginRight = "5px"; Button3.style.padding = "5px 10px"; - Button3.style.backgroundColor = this.button3Color; + Button3.style[this.button3Color.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.button3Color; Button3.style.color = this.button3TextColor; Button3.style.border = "none"; Button3.style.borderRadius = this.button3BorderRadius + "px"; @@ -1128,7 +1271,7 @@ Button4.style.marginTop = "10px"; Button4.style.marginRight = "5px"; Button4.style.padding = "5px 10px"; - Button4.style.backgroundColor = this.button4Color; + Button4.style[this.button4Color.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.button4Color; Button4.style.color = this.button4TextColor; Button4.style.border = "none"; Button4.style.borderRadius = this.button4BorderRadius + "px"; @@ -1153,7 +1296,7 @@ dropdownButton.className = "dropdown-button"; dropdownButton.textContent = this.DropdownText; dropdownButton.style.padding = "5px 10px"; - dropdownButton.style.backgroundColor = this.optionbuttonColor; + dropdownButton.style[this.optionbuttonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.optionbuttonColor; dropdownButton.style.color = this.optionbuttonTextColor; dropdownButton.style.border = "none"; dropdownButton.style.borderRadius = @@ -1172,7 +1315,7 @@ optionButton.style.marginRight = "5px"; optionButton.style.marginTop = "10px"; optionButton.style.padding = "5px 10px"; - optionButton.style.backgroundColor = this.optionbuttonColor; + optionButton.style[this.optionbuttonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.optionbuttonColor; optionButton.style.color = this.optionbuttonTextColor; optionButton.style.border = "none"; optionButton.style.borderRadius = @@ -1249,7 +1392,6 @@ }); overlay.appendChild(questionText); - if (this.isInputEnabled !== "Disabled") { if (this.isInputEnabled === "Enabled") { overlay.appendChild(inputField); @@ -1262,7 +1404,6 @@ overlay.appendChild(document.createElement("br")); } } - overlay.appendChild(submitButton); overlay.appendChild(cancelButton); overlay.appendChild(Button3); @@ -1375,6 +1516,16 @@ setImage(args) { this.overlayImage = args.IMAGE; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + scaleImage(args) { + this.imgScale = args.SCALE; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } removeOverlay(overlay) { @@ -1394,6 +1545,25 @@ document.body.removeChild(overlay); }, timeout); } + + setShadow(args) { + const shadow = args.SHADOW; + + switch(shadow) { + case 'Scale': + this.shadowS[2] = args.AMT; + break; + case 'X': + this.shadowS[0] = args.AMT; + break; + case 'Y': + this.shadowS[1] = args.AMT; + break; + case 'Opacity': + this.shadowS[3] = args.AMT; + break; + } + } } Scratch.extensions.register(new BetterInputSP()); From 66451dadf9a6bc602cf1d4f5dc4c247483a540d6 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:17:31 -0700 Subject: [PATCH 17/46] Final Changes --- extensions/SharkPool/BetterInput.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index ee77920d51..3ea625bda9 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -852,13 +852,13 @@ } return newColorType; } - + setGradient(args) { this.findGradientType(args.COLOR_TYPE); const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; this[newColorType] = gradientColor; } - + setCircleGradient(args) { this.findGradientType(args.COLOR_TYPE); const newX = args.X + 50; @@ -1545,11 +1545,11 @@ document.body.removeChild(overlay); }, timeout); } - + setShadow(args) { const shadow = args.SHADOW; - - switch(shadow) { + + switch (shadow) { case 'Scale': this.shadowS[2] = args.AMT; break; From d4c8e3da013a85df6e15f173231975c5d009dea0 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 26 Aug 2023 23:13:12 -0700 Subject: [PATCH 18/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 119 ++++++++++++++-------------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 3ea625bda9..fc8b827166 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,6 +1,6 @@ -/* +console.log("Hello, World!");/* * This extension was made by SharkPool - * Version 2.2 (Visual Effects Expansion + Fixes) + * Version 2.2.1 (Bug Fixes and Mr. Muffin Man Fixes) * Do NOT delete these comments */ @@ -29,6 +29,16 @@ let newColorType = ''; let overlayImageContainer = ''; + const fontMenu = [ + "Scratch", + "Sans Serif", + "Serif", + "Handwriting", + "Marker", + "Curly", + "Pixel", + ]; + class BetterInputSP { constructor() { this.isWaitingForInput = false; @@ -81,8 +91,6 @@ this.minSlider = 0; this.maxSlider = 100; this.defaultSlider = 50; - this.enterSpeed = 10; - this.exitSpeed = 10; this.activeOverlays = []; this.Blur = 0; this.Brightness = 0; @@ -631,15 +639,7 @@ }, fontMenu: { acceptReporters: true, - items: [ - "Scratch", - "Sans Serif", - "Serif", - "Handwriting", - "Marker", - "Curly", - "Pixel" - ], + items: "allFonts", }, buttonActionMenu: { acceptReporters: true, @@ -717,6 +717,20 @@ }; } + allFonts() { + const customFonts = Scratch.vm.runtime.fontManager + ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({ + text: i.name, + value: i.family, + })) + : []; + + return [ + ...fontMenu, + ...customFonts, + ]; + } + isWaitingInput(args) { return this.isWaitingForInput; } @@ -936,7 +950,7 @@ this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); + this.updateOverlayPos(overlay); }); } @@ -945,17 +959,33 @@ this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) * -1; this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); + this.updateOverlayPos(overlay); }); } - updateOverlay(overlay) { + updateOverlayPos(overlay) { if (this.Rotation > 359) { this.Rotation = 0; } else if (this.Rotation < 1) { this.Rotation = 360; } + overlay.style.transform = ` + SkewX(${this.SkewX}deg) + SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) + `; + + if (this.textBoxX !== null && this.textBoxY !== null) { + overlay.style.left = `${41 + this.textBoxX}%`; + overlay.style.top = `${44 + this.textBoxY}%`; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } + } + + updateOverlay(overlay) { const newOpacity = this.Opacity / 100; const newScale = this.Scale / 100; const newBrightness = this.Brightness + 100; @@ -976,17 +1006,16 @@ `; overlay.style.opacity = newOpacity; overlay.style.scale = newScale; - - overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; - overlayImageContainer.style.backgroundSize = this.imgScale + '%'; - - if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; - } else { - overlay.style.left = "50%"; - overlay.style.top = "50%"; - } + + Scratch.canFetch(encodeURI(this.overlayImage)) + .then(canFetch => { + if (canFetch) { + overlayImageContainer.style.background = `url(${encodeURI(this.overlayImage)})`; + overlayImageContainer.style.backgroundSize = this.imgScale + '%'; + } else { + console.log("Cannot fetch content from the URL."); + } + }); } setMaxBoxCount(args) { @@ -1067,18 +1096,15 @@ askAndWaitForInput(args) { if (this.askBoxCount < this.maxBoxCount) { - return new Promise((resolve) => { - this.askAndWait(args).then(() => { - resolve(this.getUserInput()); - }); + return this.askAndWait(args).then(() => { + return this.getUserInput(); }); } } removeAskBoxes() { - const askBoxes = document.querySelectorAll(".ask-box"); - askBoxes.forEach((box) => { - box.parentNode.removeChild(box); + this.activeOverlays.forEach((overlay) => { + overlay.parentNode.removeChild(overlay); }); if (this.askBoxPromise) { @@ -1119,8 +1145,6 @@ overlay.style.fontFamily = this.fontFamily; overlayImageContainer = document.createElement("div"); - overlayImageContainer.style.background = `url("${encodeURI(this.overlayImage)}")`; - overlayImageContainer.style.backgroundSize = this.imgScale + '%'; overlayImageContainer.style.width = '100%'; overlayImageContainer.style.height = '100%'; overlayImageContainer.style.position = "absolute"; @@ -1377,7 +1401,6 @@ slider.min = this.minSlider; slider.max = this.maxSlider; slider.value = this.defaultSlider; - sliderContainer.appendChild(slider); const valueDisplay = document.createElement("span"); @@ -1413,13 +1436,6 @@ document.body.appendChild(overlay); inputField.focus(); - if (this.enterEffect) { - this.applyEnterEffect(overlay); - } else { - overlay.style.opacity = "1"; - overlay.style.transform = "scale(1)"; - } - const resizeHandler = () => { if (this.textBoxX !== null && this.textBoxY !== null) { overlay.style.left = `${41 + this.textBoxX}%`; @@ -1437,7 +1453,6 @@ this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); - overlay.style.transform = `rotate(${this.Rotation - 90}deg)`; }); const observer = new MutationObserver((mutationsList) => { @@ -1500,20 +1515,6 @@ this.splitKey = args.SPLITTER; } - setEnterSpeed(args) { - this.enterSpeed = Math.abs(args.SPEED); - if (this.enterSpeed < 1) { - this.enterSpeed = 1; - } - } - - setExitSpeed(args) { - this.exitSpeed = Math.abs(args.SPEED); - if (this.exitSpeed < 1) { - this.exitSpeed = 1; - } - } - setImage(args) { this.overlayImage = args.IMAGE; this.activeOverlays.forEach((overlay) => { From e8a72ca7e787254e4ffaa44762ea2c9c548c6a10 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 26 Aug 2023 23:13:57 -0700 Subject: [PATCH 19/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index fc8b827166..9bad12b39a 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,8 +1,8 @@ -console.log("Hello, World!");/* - * This extension was made by SharkPool - * Version 2.2.1 (Bug Fixes and Mr. Muffin Man Fixes) - * Do NOT delete these comments - */ +/* +* This extension was made by SharkPool +* Version 2.2.1 (Bug Fixes and Mr. Muffin Man Fixes) +* Do NOT delete these comments +*/ (function (Scratch) { "use strict"; From 016b315e76394ab2f165176bb26a011c998acd28 Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:48:51 -0700 Subject: [PATCH 20/46] Update BetterInput.js (3.0) --- extensions/SharkPool/BetterInput.js | 1343 +++++++++++++-------------- 1 file changed, 666 insertions(+), 677 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 9bad12b39a..f39f4abd6d 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,8 +1,9 @@ -/* -* This extension was made by SharkPool -* Version 2.2.1 (Bug Fixes and Mr. Muffin Man Fixes) -* Do NOT delete these comments -*/ +// Name: Better Input +// ID: BetterInputSP +// Description: Expansion of the "ask and wait" Blocks +// By: SharkPool + +// Version V.3.0.0 (Infinite Buttons + More Live Updated Elements + Image setting for Buttons) (function (Scratch) { "use strict"; @@ -12,23 +13,22 @@ } const menuIconURI = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; const blockIconURI = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; const formatIcon = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; const colorIcon = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; const effectIcon = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; - - let newColorType = ''; - let overlayImageContainer = ''; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + let newColorType = ""; + let overlayImageContainer = ""; const fontMenu = [ "Scratch", "Sans Serif", @@ -36,62 +36,60 @@ "Handwriting", "Marker", "Curly", - "Pixel", + "Pixel" ]; class BetterInputSP { constructor() { + this.activeOverlays = []; + this.activeUI = []; + this.askBoxPromises = []; this.isWaitingForInput = false; this.isDropdownOpen = false; this.userInput = " "; - this.fontSize = "14px"; - this.questionColor = "#000000"; - this.inputColor = "#000000"; - this.textBoxColor = "#ffffff"; - this.inputBackgroundColor = "#ffffff"; - this.inputOutlineColor = "#000000"; - this.textAlign = "left"; - this.fontFamily = "Sans Serif"; - this.showCancelButton = true; - this.showButton3 = false; - this.showButton4 = false; - this.shadowEnabled = true; - this.submitButtonText = "Submit"; - this.cancelButtonText = "Cancel"; - this.Button3Text = "Okay"; - this.Button4Text = "No"; - this.DropdownText = "Dropdown"; - this.submitButtonColor = "#0074D9"; - this.cancelButtonColor = "#d9534f"; - this.button3Color = "#0074D9"; - this.button4Color = "#d9534f"; - this.optionbuttonColor = "#5f5f5f"; - this.cancelButtonBorderRadius = 5; - this.submitButtonBorderRadius = 5; - this.button3BorderRadius = 5; - this.button4BorderRadius = 5; - this.optionbuttonBorderRadius = 5; - this.submitButtonTextColor = "#ffffff"; - this.cancelButtonTextColor = "#ffffff"; - this.button3TextColor = "#ffffff"; - this.button4TextColor = "#ffffff"; - this.optionbuttonTextColor = "#ffffff"; - this.textBoxBorderRadius = 5; - this.inputBoxRadius = 4; - this.isInputEnabled = "Enabled"; this.textBoxX = 0; this.textBoxY = 0; - this.askBoxCount = 0; - this.maxBoxCount = 1; + this.askBoxInfo = [0, 1]; this.forceInput = "Disabled"; this.overlayInput = null; - this.overlayImage = null; - this.optionList = "Option 1,Option 2,Option 3"; - this.splitKey = ","; - this.minSlider = 0; - this.maxSlider = 100; - this.defaultSlider = 50; - this.activeOverlays = []; + + this.optionList = ["Option 1", "Option 2", "Option 3"]; + this.sliderInfo = [0, 100, 50]; + this.Timeout = 0; + + this.shadowEnabled = true; + this.isInputEnabled = "Enabled"; + this.DropdownText = "Dropdown"; + this.fontSize = "14px"; + this.textAlign = "left"; + this.fontFamily = "Sans Serif"; + this.overlayBorderRadius = [5, 4, 5]; + this.buttonJSON = { + "Submit": { + borderRadius: 5, + color: "#0074D9", + textColor: "#ffffff", + name: "Submit", + image: "", + imgScale: 100, + }, + "Cancel": { + borderRadius: 5, + color: "#d9534f", + textColor: "#ffffff", + name: "Cancel", + image: "", + imgScale: 100, + }, + }; + + this.questionColor = "#000000"; + this.inputColor = "#000000"; + this.textBoxColor = ["#ffffff"]; + this.inputFieldColor = ["#ffffff", "#000000"]; + this.dropdownButtonColor = ["#5f5f5f", "#ffffff"]; + this.overlayImage = [" ", " ", " "]; + this.Blur = 0; this.Brightness = 0; this.Opacity = 100; @@ -104,9 +102,8 @@ this.SkewX = 0; this.SkewY = 0; this.Rotation = 90; - this.Timeout = 0; - this.imgScale = 100; - this.shadowS = ['0','0','5','0.3']; + this.imgScale = [100, 100, 100]; + this.shadowS = [0, 0, 5, 0.3]; } getInfo() { @@ -114,6 +111,8 @@ id: "BetterInputSP", name: "Better Input", color1: "#9400ff", + color2: "#7600cc", + color3: "#8500e6", menuIconURI, blockIconURI, blocks: [ @@ -154,59 +153,21 @@ text: "remove all ask boxes", }, { - opcode: "setButtonText", - blockType: Scratch.BlockType.COMMAND, - text: "set [BUTTON_MENU] text to [TEXT]", - arguments: { - BUTTON_MENU: { - type: Scratch.ArgumentType.STRING, - menu: "buttonMenu", - defaultValue: "Button 1", - }, - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: "Submit", - }, - }, - }, - { - opcode: "setDropdown", - blockType: Scratch.BlockType.COMMAND, - text: "set dropdown options to list: [DROPDOWN] split by [SPLITTER]", - arguments: { - DROPDOWN: { - type: Scratch.ArgumentType.STRING, - defaultValue: "option 1,option 2,option 3", - }, - SPLITTER: { - type: Scratch.ArgumentType.STRING, - defaultValue: ",", - }, - }, + blockType: Scratch.BlockType.LABEL, + text: "Formatting", }, { - opcode: "setSlider", + opcode: "setFontSize", blockType: Scratch.BlockType.COMMAND, - text: "set slider to min: [MIN] max: [MAX] default: [DEFAULT]", + text: "set font size to [SIZE]", + blockIconURI: formatIcon, arguments: { - MIN: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: "0", - }, - MAX: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: "100", - }, - DEFAULT: { + SIZE: { type: Scratch.ArgumentType.NUMBER, - defaultValue: "50", + defaultValue: 14, }, }, }, - { - blockType: Scratch.BlockType.LABEL, - text: "Formatting", - }, { opcode: "setTextAlignment", blockType: Scratch.BlockType.COMMAND, @@ -242,37 +203,76 @@ ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu", - defaultValue: "Enabled", + defaultValue: "Text", }, }, }, { - opcode: "setEnable", + opcode: "setDropdown", blockType: Scratch.BlockType.COMMAND, - text: "set [ENABLE_MENU] to be [ACTION]", + text: "set dropdown options to array: [DROPDOWN]", blockIconURI: formatIcon, arguments: { - ENABLE_MENU: { + DROPDOWN: { type: Scratch.ArgumentType.STRING, - menu: "enableMenu", - defaultValue: "Button 2", + defaultValue: "[\"Option 1\", \"Option 2\", \"Option 3\"]", }, - ACTION: { + }, + }, + { + opcode: "setSlider", + blockType: Scratch.BlockType.COMMAND, + text: "set slider to min: [MIN] max: [MAX] default: [DEFAULT]", + blockIconURI: formatIcon, + arguments: { + MIN: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + MAX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 100, + }, + DEFAULT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 50, + }, + }, + }, + + "---", + + { + opcode: "setButton", + blockType: Scratch.BlockType.COMMAND, + text: "[BUTTON] button named [NAME]", + blockIconURI: formatIcon, + arguments: { + BUTTON: { type: Scratch.ArgumentType.STRING, - menu: "buttonActionMenu", - defaultValue: "Enabled", + menu: "buttonType", + defaultValue: "add", + }, + NAME: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Submit", }, }, }, { - opcode: "setFontSize", + opcode: "setButtonText", blockType: Scratch.BlockType.COMMAND, - text: "set font size to [SIZE]", + text: "set [BUTTON_MENU] button name to [TEXT]", blockIconURI: formatIcon, arguments: { - SIZE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 14, + BUTTON_MENU: { + type: Scratch.ArgumentType.STRING, + menu: "buttonMenu", + defaultValue: "Dropdown", + }, + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "my dropdown", }, }, }, @@ -383,7 +383,7 @@ COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "colorSettingsMenu", - defaultValue: "Question", + defaultValue: "Textbox", }, COLOR: { type: Scratch.ArgumentType.COLOR, @@ -391,23 +391,6 @@ }, }, }, - { - opcode: "setShadow", - blockType: Scratch.BlockType.COMMAND, - text: "set shadow [SHADOW] to [AMT]", - blockIconURI: colorIcon, - arguments: { - SHADOW: { - type: Scratch.ArgumentType.STRING, - menu: "shadowStuff", - defaultValue: "Scale", - }, - AMT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: "5", - }, - }, - }, { opcode: "setGradient", blockType: Scratch.BlockType.COMMAND, @@ -463,7 +446,40 @@ }, }, - '---', + "---", + + { + opcode: "enableShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set box shadow to be [ACTION]", + blockIconURI: colorIcon, + arguments: { + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "buttonActionMenu", + defaultValue: "Enabled", + }, + }, + }, + { + opcode: "setShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set box shadow [SHADOW] to [AMT]", + blockIconURI: colorIcon, + arguments: { + SHADOW: { + type: Scratch.ArgumentType.STRING, + menu: "shadowStuff", + defaultValue: "Size", + }, + AMT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + }, + }, + }, + + "---", { opcode: "setBorderRadius", @@ -483,14 +499,19 @@ }, }, - '---', + "---", { opcode: "setImage", blockType: Scratch.BlockType.COMMAND, - text: "set background image to [IMAGE]", + text: "set [ELEMENT] image to [IMAGE]", blockIconURI: colorIcon, arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, IMAGE: { type: Scratch.ArgumentType.STRING, defaultValue: "input-url-or-uri-here", @@ -500,9 +521,14 @@ { opcode: "scaleImage", blockType: Scratch.BlockType.COMMAND, - text: "scale background image to [SCALE]%", + text: "scale [ELEMENT] image to [SCALE]%", blockIconURI: colorIcon, arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + defaultValue: "Textbox", + }, SCALE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100, @@ -566,6 +592,9 @@ }, }, }, + + "---", + { opcode: "setTimeout", blockType: Scratch.BlockType.COMMAND, @@ -591,12 +620,12 @@ { opcode: "isWaitingInput", blockType: Scratch.BlockType.BOOLEAN, - text: "is wating for Input?", + text: "is waiting?", }, { opcode: "isDropdown", blockType: Scratch.BlockType.BOOLEAN, - text: "is dropdown menu open?", + text: "is dropdown open?", }, { opcode: "setSubmitEvent", @@ -622,14 +651,16 @@ }, }, { - opcode: "getBoxCount", - blockType: Scratch.BlockType.REPORTER, - text: "box count", - }, - { - opcode: "getMaxCount", + opcode: "getBoxInfo", blockType: Scratch.BlockType.REPORTER, - text: "box limit", + text: "box [INFO]", + arguments: { + INFO: { + type: Scratch.ArgumentType.STRING, + menu: "boxInfo", + defaultValue: "count", + }, + }, }, ], menus: { @@ -637,6 +668,14 @@ acceptReporters: true, items: ["left", "right", "center"], }, + boxInfo: { + acceptReporters: true, + items: ["count", "limit"], + }, + buttonType: { + acceptReporters: true, + items: ["add", "remove"], + }, fontMenu: { acceptReporters: true, items: "allFonts", @@ -647,7 +686,14 @@ }, inputActionMenu: { acceptReporters: true, - items: ["Enabled", "Disabled", "Dropdown", "Multi-Select Dropdown", "Slider"], + items: [ + "Text", + "None", + "Dropdown", + "Multi-Select Dropdown", + "Horizontal Slider", + "Vertical Slider" + ], }, effectMenu: { acceptReporters: true, @@ -667,47 +713,33 @@ }, shadowStuff: { acceptReporters: true, - items: ["Scale", "X", "Y", "Opacity"], + items: ["Size", "X", "Y", "Opacity"], }, buttonMenu: { acceptReporters: true, - items: ["Button 1", "Button 2", "Button 3", "Button 4", "Dropdown"], - }, - enableMenu: { - acceptReporters: true, - items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"], + items: this.allButtons([ + "Dropdown" + ], false), }, elementMenu: { acceptReporters: true, - items: [ + items: this.allButtons([ "Textbox", "Input Box", - "Button 1", - "Button 2", - "Button 3", - "Button 4", - "Dropdown Buttons", - ], + "Dropdown Button", + ], false), }, colorSettingsMenu: { acceptReporters: true, - items: [ - "Question", - "Input Text", + items: this.allButtons([ "Textbox", - "Input Background", + "Question Text", + "Input Text", + "Input Box", "Input Outline", - "Button 1", - "Button 2", - "Button 3", - "Button 4", - "Dropdown Buttons", - "Button 1 Text", - "Button 2 Text", - "Button 3 Text", - "Button 4 Text", + "Dropdown Button", "Dropdown Text", - ], + ], true), }, enterMenu: { acceptReporters: true, @@ -724,19 +756,134 @@ value: i.family, })) : []; - return [ ...fontMenu, ...customFonts, ]; } - isWaitingInput(args) { - return this.isWaitingForInput; + allButtons(array, enableText) { + const customButtons = Object.keys(this.buttonJSON); + if (enableText) { + customButtons.forEach((button) => { + customButtons.push(button + " Text"); + }); + } + return [ + ...array, + ...customButtons, + ]; } - isDropdown(args) { - return this.isDropdownOpen; + updateOverlayPos(overlay) { + if (this.Rotation > 359) { + this.Rotation = 0; + } else if (this.Rotation < 1) { + this.Rotation = 360; + } + + if (this.textBoxX !== null && this.textBoxY !== null) { + overlay.style.left = `${50 + this.textBoxX}%`; + overlay.style.top = `${50 + this.textBoxY}%`; + overlay.style.transform = ` + translate(-50%, -50%) + SkewX(${this.SkewX}deg) + SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) + scale(${this.Scale / 100}) + `; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } + } + + updateOverlay(overlay) { + const newOpacity = this.Opacity / 100; + const newBrightness = this.Brightness + 100; + overlay.style.backgroundImage = ""; + overlay.style[this.textBoxColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.textBoxColor[0]; + overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px rgba(0, 0, 0, ${this.shadowS[3]})` : "none"; + + overlay.style.transform = ` + translate(-50%, -50%) + SkewX(${this.SkewX}deg) + SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) + scale(${this.Scale / 100}) + `; + overlay.style.filter = ` + blur(${this.Blur}px) + brightness(${newBrightness}%) + invert(${this.Invert}%) + saturate(${this.Saturation}%) + hue-rotate(${this.Hue}deg) + sepia(${this.Sepia}%) + contrast(${this.Contrast}%) + `; + overlay.style.opacity = newOpacity; + overlay.style.fontFamily = this.fontFamily; + overlay.style.textAlign = this.textAlign; + overlay.style.borderRadius = this.overlayBorderRadius[0] + "px"; + overlayImageContainer.style.borderRadius = this.overlayBorderRadius[0] + "px"; + overlayImageContainer.style.background = ""; + this.setImageStyles(overlayImageContainer, this.overlayImage[0], this.imgScale[0]); + this.updateButtonImages(overlay); + } + + updateButtonImages(overlay) { + let text = overlay.querySelector(".question"); + if (text) { + text.style.color = this.questionColor; + } + + const inputField = overlay.querySelector("input"); + if (inputField) { + inputField.style.background = ""; + inputField.style[this.inputFieldColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.inputFieldColor[0]; + inputField.style.color = this.inputColor; + inputField.style.border = `1px solid ${this.inputFieldColor[1]}`; + inputField.style.borderRadius = this.overlayBorderRadius[1] + "px"; + this.setImageStyles(inputField, this.overlayImage[1], this.imgScale[1]); + } + + const dropdownButton = overlay.querySelector("button.dropbtn"); + if (dropdownButton) { + dropdownButton.style.backgroundImage = ""; + dropdownButton.style.color = this.dropdownButtonColor[1]; + dropdownButton.style.borderRadius = this.overlayBorderRadius[2] + "px"; + dropdownButton.style[this.dropdownButtonColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdownButtonColor[0]; + this.setImageStyles(dropdownButton, this.overlayImage[2], this.imgScale[2]); + } + + const buttonContainer = overlay.querySelector(".button-container"); + if (buttonContainer) { + const buttons = buttonContainer.querySelectorAll("button"); + buttons.forEach((button, index) => { + const buttonName = Object.keys(this.buttonJSON)[index]; + const buttonInfo = this.buttonJSON[buttonName]; + if (buttonInfo) { + button.style.color = buttonInfo.textColor; + button.style.borderRadius = buttonInfo.borderRadius + "px"; + button.style.background = ""; + button.style[buttonInfo.color.includes("gradient") ? "backgroundImage" : "background"] = buttonInfo.color; + this.setImageStyles(button, buttonInfo.image, buttonInfo.imgScale); + } + }); + } + } + + setImageStyles(element, url, scale) { + if (Scratch.Cast.toString(url).length > 5) { + Scratch.canFetch(encodeURI(url)).then((canFetch) => { + if (canFetch) { + element.style.background = `url(${encodeURI(url)})`; + element.style.backgroundSize = scale + "%"; + } else { + console.log("Cannot fetch content from the URL."); + } + }); + } } showEffect(args) { @@ -747,7 +894,6 @@ setEffect(args) { const effect = args.EFFECT; this[effect] = args.AMT; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); }); @@ -756,13 +902,12 @@ changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); }); } - resetEffect(args) { + resetEffect() { this.Blur = 0; this.Brightness = 0; this.Opacity = 100; @@ -783,145 +928,186 @@ setColorSettings(args) { const colorType = args.COLOR_TYPE; const colorValue = args.COLOR; - switch (colorType) { - case "Question": + case "Question Text": this.questionColor = colorValue; break; case "Input Text": this.inputColor = colorValue; break; case "Textbox": - this.textBoxColor = colorValue; - this.overlayImage = null; + this.textBoxColor[0] = colorValue; + this.overlayImage[0] = " "; break; - case "Input Background": - this.inputBackgroundColor = colorValue; + case "Input Box": + this.inputFieldColor[0] = colorValue; + this.overlayImage[1] = " "; break; case "Input Outline": - this.inputOutlineColor = colorValue; - break; - case "Button 1": - this.submitButtonColor = colorValue; - break; - case "Button 2": - this.cancelButtonColor = colorValue; - break; - case "Button 3": - this.button3Color = colorValue; - break; - case "Button 4": - this.button4Color = colorValue; - break; - case "Dropdown Buttons": - this.optionbuttonColor = colorValue; + this.inputFieldColor[1] = colorValue; break; - case "Slider": - this.sliderColor = colorValue; - break; - case "Button 1 Text": - this.submitButtonTextColor = colorValue; - break; - case "Button 2 Text": - this.cancelButtonTextColor = colorValue; - break; - case "Button 3 Text": - this.button3TextColor = colorValue; - break; - case "Button 4 Text": - this.button4TextColor = colorValue; + case "Dropdown Button": + this.dropdownButtonColor[0] = colorValue; + this.overlayImage[2] = " "; break; case "Dropdown Text": - this.optionbuttonTextColor = colorValue; + this.dropdownButtonColor[1] = colorValue; + break; + default: + if (this.buttonJSON[colorType] || this.buttonJSON[colorType.replace(" Text", "")]) { + let buttonInfo; + if (colorType.includes(" Text")) { + buttonInfo = this.buttonJSON[colorType.replace(" Text", "")]; + buttonInfo.textColor = colorValue; + } else { + buttonInfo = this.buttonJSON[colorType]; + buttonInfo.color = colorValue; + buttonInfo.image = " "; + } + } break; } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } findGradientType(menu) { const colorType = menu; - switch (colorType) { case "Textbox": - newColorType = 'textBoxColor'; - this.overlayImage = null; - break; + newColorType = "textBoxColor"; + this.overlayImage[0] = " "; + return newColorType; case "Input Box": - newColorType = 'inputBackgroundColor'; - break; - case "Button 1": - newColorType = 'submitButtonColor'; - break; - case "Button 2": - newColorType = 'cancelButtonColor'; - break; - case "Button 3": - newColorType = 'button3Color'; - break; - case "Button 4": - newColorType = 'button4Color'; - break; - case "Dropdown Buttons": - newColorType = 'optionbuttonColor'; - break; + newColorType = "inputFieldColor"; + this.overlayImage[1] = " "; + return newColorType; + case "Dropdown Button": + newColorType = "dropdownButtonColor"; + this.overlayImage[2] = " "; + return newColorType; + default: + if (this.buttonJSON[colorType]) { + newColorType = ["button", colorType]; + } + return newColorType; } - return newColorType; } setGradient(args) { - this.findGradientType(args.COLOR_TYPE); + const newColorType = this.findGradientType(args.COLOR_TYPE); const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; - this[newColorType] = gradientColor; + if (newColorType[0] !== "button") { + this[newColorType][0] = gradientColor; + } else { + const buttonInfo = this.buttonJSON[newColorType[1]]; + buttonInfo.color = gradientColor; + } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } setCircleGradient(args) { - this.findGradientType(args.COLOR_TYPE); - const newX = args.X + 50; - const newY = args.Y + 50; - - const gradientColor = `radial-gradient(circle at ${newX}% ${newY}%, ${args.COLOR2}, ${args.COLOR1})`; - this[newColorType] = gradientColor; + const newColorType = this.findGradientType(args.COLOR_TYPE); + const newPos = [args.X + 50, args.Y + 50]; + const gradientColor = `radial-gradient(circle at ${newPos[0]}% ${newPos[1]}%, ${args.COLOR2}, ${args.COLOR1})`; + if (newColorType[0] !== "button") { + this[newColorType][0] = gradientColor; + } else { + const buttonInfo = this.buttonJSON[newColorType[1]]; + buttonInfo.color = gradientColor; + } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } setBorderRadius(args) { const element = args.ELEMENT; let value = args.VALUE; - if (value < 0) { value = 0; } - switch (element) { case "Textbox": - this.textBoxBorderRadius = value; + this.overlayBorderRadius[0] = value; break; - case "Button 1": - this.submitButtonBorderRadius = value; + case "Input Box": + this.overlayBorderRadius[1] = value; break; - case "Button 2": - this.cancelButtonBorderRadius = value; + case "Dropdown Button": + this.overlayBorderRadius[2] = value; break; - case "Button 3": - this.button3BorderRadius = value; + default: + if (this.buttonJSON[element]) { + const buttonInfo = this.buttonJSON[element]; + buttonInfo.borderRadius = value; + } break; - case "Button 4": - this.button4BorderRadius = value; + } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + setShadow(args) { + const shadow = args.SHADOW; + switch (shadow) { + case "Size": + this.shadowS[2] = args.AMT; break; - case "Input Box": - this.inputBoxRadius = value; + case "X": + this.shadowS[0] = args.AMT; break; - case "Dropdown Buttons": - this.optionbuttonBorderRadius = value; + case "Y": + this.shadowS[1] = args.AMT; break; - case "Slider": - this.sliderBorderRadius = value; + case "Opacity": + this.shadowS[3] = args.AMT / 100; break; } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + setImage(args) { + if (args.ELEMENT === "Textbox") { + this.overlayImage[0] = args.IMAGE; + } else if (args.ELEMENT === "Input Box") { + this.overlayImage[1] = args.IMAGE; + } else if (args.ELEMENT === "Dropdown Button") { + this.overlayImage[2] = args.IMAGE; + } else if (this.buttonJSON[args.ELEMENT]) { + const buttonInfo = this.buttonJSON[args.ELEMENT]; + buttonInfo.image = args.IMAGE; + } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + scaleImage(args) { + if (args.ELEMENT === "Textbox") { + this.imgScale[0] = args.SCALE; + } else if (args.ELEMENT === "Input Box") { + this.imgScale[1] = args.SCALE; + } else if (args.ELEMENT === "Dropdown Button") { + this.imgScale[2] = args.SCALE; + } else if (this.buttonJSON[args.ELEMENT]) { + const buttonInfo = this.buttonJSON[args.ELEMENT]; + buttonInfo.imgScale = args.SCALE; + } + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } setDirection(args) { const ROTATE = args.ROTATE; this.Rotation = Scratch.Cast.toNumber(ROTATE); - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); }); @@ -930,96 +1116,42 @@ changeDirection(args) { const ROTATE = args.ROTATE; this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay); }); } - reportDirection(args) { + reportDirection() { return this.Rotation; } setPrePosition(args) { - this.textBoxX = Scratch.Cast.toNumber(args.X); - this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; + this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); } setPosition(args) { - this.textBoxX = Scratch.Cast.toNumber(args.X); - this.textBoxY = Scratch.Cast.toNumber(args.Y) * -1; - + this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay); }); } changePosition(args) { - this.textBoxX = this.textBoxX + Scratch.Cast.toNumber(args.X); - this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) * -1; - + this.textBoxX = this.textBoxX + Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) / (screen.height / -300); this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay); }); } - updateOverlayPos(overlay) { - if (this.Rotation > 359) { - this.Rotation = 0; - } else if (this.Rotation < 1) { - this.Rotation = 360; - } - - overlay.style.transform = ` - SkewX(${this.SkewX}deg) - SkewY(${this.SkewY}deg) - rotate(${this.Rotation - 90}deg) - `; - - if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; - } else { - overlay.style.left = "50%"; - overlay.style.top = "50%"; - } - } - - updateOverlay(overlay) { - const newOpacity = this.Opacity / 100; - const newScale = this.Scale / 100; - const newBrightness = this.Brightness + 100; - - overlay.style.transform = ` - SkewX(${this.SkewX}deg) - SkewY(${this.SkewY}deg) - rotate(${this.Rotation - 90}deg) - `; - overlay.style.filter = ` - blur(${this.Blur}px) - brightness(${newBrightness}%) - invert(${this.Invert}%) - saturate(${this.Saturation}%) - hue-rotate(${this.Hue}deg) - sepia(${this.Sepia}%) - contrast(${this.Contrast}%) - `; - overlay.style.opacity = newOpacity; - overlay.style.scale = newScale; - - Scratch.canFetch(encodeURI(this.overlayImage)) - .then(canFetch => { - if (canFetch) { - overlayImageContainer.style.background = `url(${encodeURI(this.overlayImage)})`; - overlayImageContainer.style.backgroundSize = this.imgScale + '%'; - } else { - console.log("Cannot fetch content from the URL."); - } - }); + getXpos() { + return this.textBoxX * (screen.width / 400); } - setMaxBoxCount(args) { - this.maxBoxCount = args.MAX; + getYpos() { + return this.textBoxY * (screen.height / -300); } setFontSize(args) { @@ -1028,121 +1160,104 @@ setTextAlignment(args) { this.textAlign = args.ALIGNMENT; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } setFontFamily(args) { this.fontFamily = args.FONT; - } - - setTimeout(args) { - this.Timeout = args.TIME; - this.Condition = args.CONDITION; - } - - reportTimeout(args) { - return this.Timeout; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); } setSlider(args) { - this.minSlider = args.MIN; - this.maxSlider = args.MAX; - this.defaultSlider = args.DEFAULT; + this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT]; } - setEnable(args) { - const enableMenu = args.ENABLE_MENU; - const action = args.ACTION; - switch (enableMenu) { - case "Button 2": - this.showCancelButton = action === "Enabled"; - break; - case "Button 3": - this.showButton3 = action === "Enabled"; - break; - case "Button 4": - this.showButton4 = action === "Enabled"; - break; - case "Textbox Shadow": - this.shadowEnabled = action === "Enabled"; - break; + setInputType(args) { + if (args.ACTION === "Text" || args.ACTION === "None") { + this.isInputEnabled = args.ACTION === "Text" ? "Enabled" : "Disabled"; + } else { + this.isInputEnabled = args.ACTION; } } - setInputType(args) { - this.isInputEnabled = args.ACTION; + enableShadow(args) { + this.shadowEnabled = args.ACTION === "Enabled"; } setButtonText(args) { const buttonMenu = args.BUTTON_MENU; const text = args.TEXT; - switch (buttonMenu) { - case "Button 1": - this.submitButtonText = text; - break; - case "Button 2": - this.cancelButtonText = text; - break; - case "Button 3": - this.Button3Text = text; - break; - case "Button 4": - this.Button4Text = text; - break; - case "Dropdown": - this.DropdownText = text; - break; + if (buttonMenu === "Dropdown") { + this.DropdownText = text; + } else if (this.buttonJSON[buttonMenu]) { + const buttonInfo = this.buttonJSON[buttonMenu]; + buttonInfo.name = text; + Scratch.vm.extensionManager.refreshBlocks(); } } - askAndWaitForInput(args) { - if (this.askBoxCount < this.maxBoxCount) { - return this.askAndWait(args).then(() => { - return this.getUserInput(); - }); + setDropdown(args) { + try { + this.optionList = JSON.parse(args.DROPDOWN); + } catch (error) { + this.optionList = ["Undefined Array Error"]; } } removeAskBoxes() { + const overlaysToRemove = []; this.activeOverlays.forEach((overlay) => { - overlay.parentNode.removeChild(overlay); + if (overlay && overlay.parentNode) { + overlay.parentNode.removeChild(overlay); + overlaysToRemove.push(overlay); + } + if (this.askBoxPromises) { + const index = this.activeOverlays.indexOf(overlay); + if (index !== -1) { + this.askBoxPromises[index].resolve("removed"); + } + } }); + this.askBoxPromises = []; + this.activeOverlays = this.activeOverlays.filter( + (overlay) => !overlaysToRemove.includes(overlay) + ); + this.activeUI = []; + this.askBoxInfo[0] = 0; + this.userInput = ""; + } - if (this.askBoxPromise) { - this.askBoxPromise.resolve("removed"); - this.askBoxPromise = null; + askAndWaitForInput(args) { + if (this.askBoxInfo[0] < this.askBoxInfo[1] ) { + return this.askAndWait(args).then(() => { + return this.getUserInput(); + }); } - this.askBoxCount = 0; - this.userInput = ""; } askAndWait(args) { - if (this.askBoxCount < this.maxBoxCount) { + if (this.askBoxInfo[0] < this.askBoxInfo[1]) { const question = args.question; this.isWaitingForInput = true; this.userInput = null; - this.askBoxCount++; - if (this.askBoxPromise) { - this.askBoxPromise.resolve("removed"); - } - - this.askBoxPromise = {}; + this.askBoxInfo[0]++; + let selectedOptions = []; return new Promise((resolve) => { - this.askBoxPromise.resolve = resolve; + const askBoxPromise = { resolve }; + this.askBoxPromises.push(askBoxPromise); const overlay = document.createElement("div"); - this.activeOverlays.push(overlay); overlay.classList.add("ask-box"); overlay.style.position = "fixed"; - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; overlay.style.zIndex = "9999"; - overlay.style[this.textBoxColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.textBoxColor; - overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px rgba(0, 0, 0, ${this.shadowS[3]})` : "none"; - overlay.style.borderRadius = this.textBoxBorderRadius + "px"; overlay.style.padding = "15px"; overlay.style.fontSize = this.fontSize; - overlay.style.textAlign = this.textAlign; - overlay.style.fontFamily = this.fontFamily; + overlay.style.left = `${50 + this.textBoxX}%`; + overlay.style.top = `${50 + this.textBoxY}%`; overlayImageContainer = document.createElement("div"); overlayImageContainer.style.width = '100%'; @@ -1150,12 +1265,10 @@ overlayImageContainer.style.position = "absolute"; overlayImageContainer.style.top = 0; overlayImageContainer.style.left = 0; - overlayImageContainer.style.borderRadius = this.textBoxBorderRadius + "px"; overlayImageContainer.style.zIndex = "-1"; if (this.forceInput !== "Disabled") { let overlayInput; - if (this.forceInput === "Enter Key") { overlayInput = "Enter"; } else if (this.forceInput === "Shift + Enter Key") { @@ -1163,7 +1276,6 @@ } else { overlayInput = this.forceInput; } - const handleKeydown = (event) => { if ( (overlayInput === "ShiftEnter" && @@ -1171,18 +1283,11 @@ event.key === "Enter") || event.key === overlayInput ) { - if (this.isInputEnabled === "Multi-Select Dropdown") { - inputField.value = inputField.value.substring(1); - inputField.value = inputField.value.replace(this.splitKey, '", "'); - this.userInput = '["' + inputField.value + '"]'; - } else { - this.userInput = inputField.value; - } + this.userInput = inputField.value; this.closeOverlay(overlay); resolve(); } }; - const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if ( @@ -1194,7 +1299,6 @@ } } }); - observer.observe(document.body, { childList: true }); document.addEventListener("keydown", handleKeydown); } @@ -1203,7 +1307,6 @@ questionText.classList.add("question"); questionText.style.fontSize = this.fontSize; questionText.style.marginBottom = "10px"; - questionText.style.color = this.questionColor; questionText.textContent = question; const inputField = document.createElement("input"); @@ -1211,204 +1314,114 @@ inputField.style.width = "94%"; inputField.style.padding = "5px"; inputField.style.fontSize = this.fontSize; - inputField.style.color = this.inputColor; - inputField.style[this.inputBackgroundColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.inputBackgroundColor; - inputField.style.border = `1px solid ${this.inputOutlineColor}`; - inputField.style.borderRadius = this.inputBoxRadius + "px"; inputField.style.margin = "0 auto"; - inputField.style.textAlign = this.textAlign; - - const submitButton = document.createElement("button"); - submitButton.style.marginTop = "10px"; - submitButton.style.marginRight = "5px"; - submitButton.style.padding = "5px 10px"; - submitButton.style[this.submitButtonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.submitButtonColor; - submitButton.style.color = this.submitButtonTextColor; - submitButton.style.border = "none"; - submitButton.style.borderRadius = - this.submitButtonBorderRadius + "px"; - submitButton.style.cursor = "pointer"; - submitButton.textContent = this.submitButtonText; - - submitButton.addEventListener("click", () => { - if (this.isInputEnabled !== "Disabled") { - if (this.isInputEnabled === "Multi-Select Dropdown") { - inputField.value = inputField.value.substring(1); - inputField.value = inputField.value.replace(this.splitKey, '", "'); - this.userInput = '["' + inputField.value + '"]'; + + const buttonContainer = document.createElement("div"); + buttonContainer.classList.add("button-container"); + for (const buttonName in this.buttonJSON) { + const buttonInfo = this.buttonJSON[buttonName]; + if (buttonInfo.name.includes("")) { + const lineBreak = document.createElement("br"); + buttonContainer.appendChild(lineBreak); + } else { + const button = document.createElement("button"); + button.style.marginTop = "10px"; + button.style.marginRight = "5px"; + button.style.padding = "5px 10px"; + button.style.border = "none"; + button.style.cursor = "pointer"; + button.textContent = buttonInfo.name; + button.style.display = "inline-block"; + button.addEventListener("click", () => { + if (this.isInputEnabled === "Disabled") { + this.userInput = buttonInfo.name; } else { this.userInput = inputField.value; } - } else { - this.userInput = this.submitButtonText; - } - this.closeOverlay(overlay); - resolve(); - }); - - const cancelButton = document.createElement("button"); - cancelButton.style.marginTop = "10px"; - cancelButton.style.marginRight = "5px"; - cancelButton.style.padding = "5px 10px"; - cancelButton.style[this.cancelButtonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.cancelButtonColor; - cancelButton.style.color = this.cancelButtonTextColor; - cancelButton.style.border = "none"; - cancelButton.style.borderRadius = - this.cancelButtonBorderRadius + "px"; - cancelButton.style.cursor = "pointer"; - cancelButton.textContent = this.cancelButtonText; - cancelButton.style.display = this.showCancelButton ? "inline-block" : "none"; - - cancelButton.addEventListener("click", () => { - if (this.isInputEnabled === "Disabled") { - this.userInput = this.cancelButtonText; - } else { - this.userInput = ""; - } - this.closeOverlay(overlay); - resolve(); - }); - - const Button3 = document.createElement("button"); - Button3.style.marginTop = "10px"; - Button3.style.marginRight = "5px"; - Button3.style.padding = "5px 10px"; - Button3.style[this.button3Color.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.button3Color; - Button3.style.color = this.button3TextColor; - Button3.style.border = "none"; - Button3.style.borderRadius = this.button3BorderRadius + "px"; - Button3.style.cursor = "pointer"; - Button3.textContent = this.Button3Text; - Button3.style.display = this.showButton3 ? "inline-block" : "none"; - - Button3.addEventListener("click", () => { - if (this.isInputEnabled === "Disabled") { - this.userInput = this.Button3Text; - } else { - this.userInput = ""; - } - this.closeOverlay(overlay); - resolve(); - }); - - const Button4 = document.createElement("button"); - Button4.style.marginTop = "10px"; - Button4.style.marginRight = "5px"; - Button4.style.padding = "5px 10px"; - Button4.style[this.button4Color.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.button4Color; - Button4.style.color = this.button4TextColor; - Button4.style.border = "none"; - Button4.style.borderRadius = this.button4BorderRadius + "px"; - Button4.style.cursor = "pointer"; - Button4.textContent = this.Button4Text; - Button4.style.display = this.showButton4 ? "inline-block" : "none"; - - Button4.addEventListener("click", () => { - if (this.isInputEnabled === "Disabled") { - this.userInput = this.Button4Text; - } else { - this.userInput = ""; + this.closeOverlay(overlay); + resolve(); + }); + buttonContainer.appendChild(button); } - this.closeOverlay(overlay); - resolve(); - }); + } const dropdown = document.createElement("div"); dropdown.className = "dropdown"; const dropdownButton = document.createElement("button"); - dropdownButton.className = "dropdown-button"; + dropdownButton.className = "dropbtn"; dropdownButton.textContent = this.DropdownText; dropdownButton.style.padding = "5px 10px"; - dropdownButton.style[this.optionbuttonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.optionbuttonColor; - dropdownButton.style.color = this.optionbuttonTextColor; dropdownButton.style.border = "none"; - dropdownButton.style.borderRadius = - this.optionbuttonBorderRadius + "px"; const dropdownContent = document.createElement("div"); + dropdownContent.id = "myDropdown"; dropdownContent.className = "dropdown-content"; - this.isDropdownOpen = false; - - const optionList = this.optionList; - const numOfOptions = optionList.split(this.splitKey).length; - const options = this.optionList.split(this.splitKey); - const listing = Math.floor((optionList.length / 2) / numOfOptions) - 1; - for (let i = 1; i <= numOfOptions; i++) { - const optionButton = document.createElement("button"); - optionButton.style.marginRight = "5px"; - optionButton.style.marginTop = "10px"; - optionButton.style.padding = "5px 10px"; - optionButton.style[this.optionbuttonColor.includes('gradient') ? 'backgroundImage' : 'backgroundColor'] = this.optionbuttonColor; - optionButton.style.color = this.optionbuttonTextColor; - optionButton.style.border = "none"; - optionButton.style.borderRadius = - this.optionbuttonBorderRadius + "px"; - optionButton.textContent = `${options[i - 1]}`; - optionButton.style.filter = "brightness(1)"; - - optionButton.addEventListener("click", () => { + dropdownContent.style.display = "none"; + + const optionLabels = this.optionList; + optionLabels.forEach((label, index) => { + const optionLabel = document.createElement("label"); + optionLabel.style.color = this.questionColor; + optionLabel.textContent = label + " "; + const optionRadio = document.createElement("input"); + optionRadio.type = this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; + optionRadio.name = "dropdownOptions"; + optionRadio.value = index; + optionRadio.classList.add("dropdown-radio"); + optionRadio.addEventListener("click", () => { if (this.isInputEnabled === "Multi-Select Dropdown") { - const selectedOptions = inputField.value.split(this.splitKey); - const isSelected = selectedOptions.includes(options[i - 1]); - - if (isSelected) { - inputField.value = selectedOptions.filter(option => option !== options[i - 1]).join(this.splitKey); + if (selectedOptions.includes(label)) { + selectedOptions = selectedOptions.filter(item => item !== label); } else { - inputField.value = [...selectedOptions, options[i - 1]].join(this.splitKey); + selectedOptions.push(label); } - - const newSelectedOptions = inputField.value.split(this.splitKey); - for (let j = 0; j < numOfOptions; j++) { - const otherButton = dropdownContent.children[j]; - otherButton.style.filter = newSelectedOptions.includes(options[j]) ? "brightness(1.5)" : "brightness(1)"; + if (selectedOptions.length > 0) { + inputField.value = "[\"" + selectedOptions.join("\", \"") + "\"]"; + } else { + inputField.value = ""; } } else { - inputField.value = `${options[i - 1]}`; - - for (let j = 0; j < numOfOptions; j++) { - const otherButton = dropdownContent.children[j]; - otherButton.style.filter = otherButton === optionButton ? "brightness(1.5)" : "brightness(1)"; - } + inputField.value = label; } }); - dropdownContent.appendChild(optionButton); - if (i % listing === 0 && i !== numOfOptions) { - const lineBreak = document.createElement("br"); - dropdownContent.appendChild(lineBreak); - } - } - - dropdownButton.addEventListener("mouseover", () => { - if (!this.isDropdownOpen) { - overlay.insertBefore(dropdownContent, submitButton); - this.isDropdownOpen = true; - } + optionLabel.appendChild(optionRadio); + optionLabel.appendChild(document.createElement("br")); + dropdownContent.appendChild(optionLabel); }); - - overlay.addEventListener("mouseleave", () => { - if (this.isDropdownOpen) { - overlay.removeChild(dropdownContent); - this.isDropdownOpen = false; - } + document.body.appendChild(dropdown); + dropdownButton.addEventListener("click", () => { + dropdownContent.style.display = this.isDropdownOpen ? "none" : "block"; + this.isDropdownOpen = !this.isDropdownOpen; }); const sliderContainer = document.createElement("div"); sliderContainer.classList.add("slider-container"); const slider = document.createElement("input"); + if (this.isInputEnabled.includes("Vertical")) { + slider.style.transform = "rotate(270deg)"; + } slider.type = "range"; - slider.min = this.minSlider; - slider.max = this.maxSlider; - slider.value = this.defaultSlider; - sliderContainer.appendChild(slider); - + slider.min = this.sliderInfo[0]; + slider.max = this.sliderInfo[1]; + slider.value = this.sliderInfo[2]; + if (this.isInputEnabled.includes("Vertical")) { + for (let i = 0; i < 3; i++) { + sliderContainer.appendChild(document.createElement("br")); + } + sliderContainer.appendChild(slider); + for (let i = 0; i < 4; i++) { + sliderContainer.appendChild(document.createElement("br")); + } + } else { + sliderContainer.appendChild(slider); + } const valueDisplay = document.createElement("span"); valueDisplay.classList.add("slider-value"); sliderContainer.appendChild(valueDisplay); valueDisplay.style.color = this.questionColor; valueDisplay.textContent = slider.value; - slider.addEventListener("input", () => { valueDisplay.textContent = slider.value; inputField.value = valueDisplay.textContent; @@ -1418,152 +1431,128 @@ if (this.isInputEnabled !== "Disabled") { if (this.isInputEnabled === "Enabled") { overlay.appendChild(inputField); - } else if (this.isInputEnabled === "Dropdown" || this.isInputEnabled === "Multi-Select Dropdown") { - dropdown.appendChild(dropdownButton); - overlay.appendChild(dropdown); + } else if (this.isInputEnabled.includes("Dropdown")) { + overlay.appendChild(dropdownButton); + overlay.appendChild(dropdownContent); + overlay.appendChild(document.createElement("br")); } else { overlay.appendChild(sliderContainer); overlay.appendChild(valueDisplay); overlay.appendChild(document.createElement("br")); } } - overlay.appendChild(submitButton); - overlay.appendChild(cancelButton); - overlay.appendChild(Button3); - overlay.appendChild(Button4); + overlay.appendChild(buttonContainer); overlay.appendChild(overlayImageContainer); - document.body.appendChild(overlay); inputField.focus(); const resizeHandler = () => { if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${41 + this.textBoxX}%`; - overlay.style.top = `${44 + this.textBoxY}%`; + overlay.style.left = `${50 + this.textBoxX}%`; + overlay.style.top = `${50 + this.textBoxY}%`; } else { overlay.style.left = "50%"; overlay.style.top = "50%"; } }; + this.activeOverlays.push(overlay); + this.activeUI.push({ + overlay: { + button: buttonContainer, + dropdown: dropdownButton, + input: inputField, + }, + }); document.addEventListener("fullscreenchange", resizeHandler); document.addEventListener("webkitfullscreenchange", resizeHandler); document.addEventListener("mozfullscreenchange", resizeHandler); document.addEventListener("MSFullscreenChange", resizeHandler); - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); - + const overlayParent = overlay.parentNode; const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { - if ( - mutation.type === "childList" && - !document.contains(overlay) - ) { + if (mutation.type === "childList" && mutation.removedNodes.contains(overlay)) { document.removeEventListener("fullscreenchange", resizeHandler); - document.removeEventListener( - "webkitfullscreenchange", - resizeHandler, - ); - document.removeEventListener( - "mozfullscreenchange", - resizeHandler, - ); - document.removeEventListener( - "MSFullscreenChange", - resizeHandler, - ); + document.removeEventListener("webkitfullscreenchange", resizeHandler); + document.removeEventListener("mozfullscreenchange", resizeHandler); + document.removeEventListener("MSFullscreenChange", resizeHandler); observer.disconnect(); } } }); - - observer.observe(document.body, { childList: true }); + observer.observe(overlayParent, { childList: true }); document.body.appendChild(overlay); inputField.focus(); + this.updateOverlay(overlay); }); } } - getUserInput() { - return this.userInput; - } - - getBoxCount() { - return this.askBoxCount; - } - - getMaxCount() { - return this.maxBoxCount; + closeOverlay(overlay) { + if (this.askBoxInfo[0] < 2) { + this.isWaitingForInput = false; + } + this.isDropdownOpen = false; + this.askBoxInfo[0]--; + const index = this.activeOverlays.indexOf(overlay); + if (index !== -1) { + this.activeOverlays.splice(index, 1); + this.askBoxPromises.splice(index, 1); + } + delete this.activeUI[overlay]; + setTimeout(() => { + document.body.removeChild(overlay); + }, this.Timeout * 1000); } - getXpos() { - return this.textBoxX; + setButton(args) { + if (args.BUTTON === "add") { + this.buttonJSON[args.NAME] = { + borderRadius: 5, + color: "#0074D9", + textColor: "#ffffff", + name: args.NAME, + image: "", + imgScale: 100, + }; + } else { + delete this.buttonJSON[args.NAME]; + } + Scratch.vm.extensionManager.refreshBlocks() } - getYpos() { - return this.textBoxY; + isWaitingInput() { + return this.isWaitingForInput; } - setSubmitEvent(args) { - this.forceInput = args.ENTER; + isDropdown() { + return this.isDropdownOpen; } - setDropdown(args) { - this.optionList = args.DROPDOWN; - this.splitKey = args.SPLITTER; + setMaxBoxCount(args) { + this.askBoxInfo[1] = args.MAX; } - setImage(args) { - this.overlayImage = args.IMAGE; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + setTimeout(args) { + this.Timeout = args.TIME; + this.Condition = args.CONDITION; } - scaleImage(args) { - this.imgScale = args.SCALE; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + reportTimeout() { + return this.Timeout; } - removeOverlay(overlay) { - const index = this.activeOverlays.indexOf(overlay); - if (index !== -1) { - this.activeOverlays.splice(index, 1); - } - document.body.removeChild(overlay); + getUserInput() { + return this.userInput === null ? "" : this.userInput; } - closeOverlay(overlay) { - this.isWaitingForInput = false; - this.isDropdownOpen = false; - this.askBoxCount--; - const timeout = this.Timeout * 1000; - setTimeout(() => { - document.body.removeChild(overlay); - }, timeout); + getBoxInfo(args) { + return this.askBoxInfo[args.INFO === "count" ? 0 : 1]; } - setShadow(args) { - const shadow = args.SHADOW; - - switch (shadow) { - case 'Scale': - this.shadowS[2] = args.AMT; - break; - case 'X': - this.shadowS[0] = args.AMT; - break; - case 'Y': - this.shadowS[1] = args.AMT; - break; - case 'Opacity': - this.shadowS[3] = args.AMT; - break; - } + setSubmitEvent(args) { + this.forceInput = args.ENTER; } } From ee43e700db37b1a1830a1722f1c440d609a2119c Mon Sep 17 00:00:00 2001 From: SharkPool-SP <139097378+SharkPool-SP@users.noreply.github.com> Date: Mon, 9 Oct 2023 21:50:34 -0700 Subject: [PATCH 21/46] Create Better-Input.svg --- images/SharkPool/Better-Input.svg | 65 +++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 images/SharkPool/Better-Input.svg diff --git a/images/SharkPool/Better-Input.svg b/images/SharkPool/Better-Input.svg new file mode 100644 index 0000000000..d9565362d3 --- /dev/null +++ b/images/SharkPool/Better-Input.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d8695423ee9fa43761262b9ec86bc3a4e2885d3f Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 25 Nov 2023 22:32:23 -0800 Subject: [PATCH 22/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 82 ++++++++--------------------- 1 file changed, 22 insertions(+), 60 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index f39f4abd6d..27f3d6384b 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -3,7 +3,7 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.3.0.0 (Infinite Buttons + More Live Updated Elements + Image setting for Buttons) +// Version V.3.0.1 (Formatting Changes and Code Simplifications) (function (Scratch) { "use strict"; @@ -833,9 +833,7 @@ updateButtonImages(overlay) { let text = overlay.querySelector(".question"); - if (text) { - text.style.color = this.questionColor; - } + if (text) text.style.color = this.questionColor; const inputField = overlay.querySelector("input"); if (inputField) { @@ -880,7 +878,7 @@ element.style.background = `url(${encodeURI(url)})`; element.style.backgroundSize = scale + "%"; } else { - console.log("Cannot fetch content from the URL."); + console.log("Cannot fetch content from the URL"); } }); } @@ -1027,9 +1025,7 @@ setBorderRadius(args) { const element = args.ELEMENT; let value = args.VALUE; - if (value < 0) { - value = 0; - } + if (value < 0) value = 0; switch (element) { case "Textbox": this.overlayBorderRadius[0] = value; @@ -1121,9 +1117,7 @@ }); } - reportDirection() { - return this.Rotation; - } + reportDirection() { return this.Rotation } setPrePosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); @@ -1146,17 +1140,11 @@ }); } - getXpos() { - return this.textBoxX * (screen.width / 400); - } + getXpos() { return this.textBoxX * (screen.width / 400) } - getYpos() { - return this.textBoxY * (screen.height / -300); - } + getYpos() { return this.textBoxY * (screen.height / -300) } - setFontSize(args) { - this.fontSize = args.SIZE + "px"; - } + setFontSize(args) { this.fontSize = args.SIZE + "px" } setTextAlignment(args) { this.textAlign = args.ALIGNMENT; @@ -1172,9 +1160,7 @@ }); } - setSlider(args) { - this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT]; - } + setSlider(args) { this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT] } setInputType(args) { if (args.ACTION === "Text" || args.ACTION === "None") { @@ -1184,9 +1170,7 @@ } } - enableShadow(args) { - this.shadowEnabled = args.ACTION === "Enabled"; - } + enableShadow(args) { this.shadowEnabled = args.ACTION === "Enabled" } setButtonText(args) { const buttonMenu = args.BUTTON_MENU; @@ -1217,9 +1201,7 @@ } if (this.askBoxPromises) { const index = this.activeOverlays.indexOf(overlay); - if (index !== -1) { - this.askBoxPromises[index].resolve("removed"); - } + if (index !== -1) this.askBoxPromises[index].resolve("removed"); } }); this.askBoxPromises = []; @@ -1353,7 +1335,6 @@ dropdownButton.textContent = this.DropdownText; dropdownButton.style.padding = "5px 10px"; dropdownButton.style.border = "none"; - const dropdownContent = document.createElement("div"); dropdownContent.id = "myDropdown"; dropdownContent.className = "dropdown-content"; @@ -1363,7 +1344,7 @@ optionLabels.forEach((label, index) => { const optionLabel = document.createElement("label"); optionLabel.style.color = this.questionColor; - optionLabel.textContent = label + " "; + optionLabel.textContent = ""; const optionRadio = document.createElement("input"); optionRadio.type = this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; optionRadio.name = "dropdownOptions"; @@ -1376,16 +1357,13 @@ } else { selectedOptions.push(label); } - if (selectedOptions.length > 0) { - inputField.value = "[\"" + selectedOptions.join("\", \"") + "\"]"; - } else { - inputField.value = ""; - } + inputField.value = selectedOptions.length > 0 ? JSON.stringify(selectedOptions) : ""; } else { inputField.value = label; } }); optionLabel.appendChild(optionRadio); + optionLabel.appendChild(document.createTextNode(" " + label)); optionLabel.appendChild(document.createElement("br")); dropdownContent.appendChild(optionLabel); }); @@ -1490,9 +1468,7 @@ } closeOverlay(overlay) { - if (this.askBoxInfo[0] < 2) { - this.isWaitingForInput = false; - } + if (this.askBoxInfo[0] < 2) this.isWaitingForInput = false; this.isDropdownOpen = false; this.askBoxInfo[0]--; const index = this.activeOverlays.indexOf(overlay); @@ -1522,38 +1498,24 @@ Scratch.vm.extensionManager.refreshBlocks() } - isWaitingInput() { - return this.isWaitingForInput; - } + isWaitingInput() { return this.isWaitingForInput } - isDropdown() { - return this.isDropdownOpen; - } + isDropdown() { return this.isDropdownOpen } - setMaxBoxCount(args) { - this.askBoxInfo[1] = args.MAX; - } + setMaxBoxCount(args) { this.askBoxInfo[1] = args.MAX } setTimeout(args) { this.Timeout = args.TIME; this.Condition = args.CONDITION; } - reportTimeout() { - return this.Timeout; - } + reportTimeout() { return this.Timeout } - getUserInput() { - return this.userInput === null ? "" : this.userInput; - } + getUserInput() { return this.userInput === null ? "" : this.userInput } - getBoxInfo(args) { - return this.askBoxInfo[args.INFO === "count" ? 0 : 1]; - } + getBoxInfo(args) { return this.askBoxInfo[args.INFO === "count" ? 0 : 1] } - setSubmitEvent(args) { - this.forceInput = args.ENTER; - } + setSubmitEvent(args) { this.forceInput = args.ENTER } } Scratch.extensions.register(new BetterInputSP()); From 1428caa56a045d4355f1296c2f3a190123a9ef52 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Wed, 6 Dec 2023 14:23:58 -0800 Subject: [PATCH 23/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 170 +++++++++------------------- 1 file changed, 54 insertions(+), 116 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 27f3d6384b..8347da4aba 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -1,16 +1,14 @@ // Name: Better Input // ID: BetterInputSP // Description: Expansion of the "ask and wait" Blocks -// By: SharkPool +// By: SharkPool -// Version V.3.0.1 (Formatting Changes and Code Simplifications) +// Version V.3.0.2 (Bug Fixes and New Blocks) (function (Scratch) { "use strict"; - if (!Scratch.extensions.unsandboxed) { - throw new Error("Better Input must run unsandboxed"); - } + if (!Scratch.extensions.unsandboxed) throw new Error("Better Input must run unsandboxed"); const menuIconURI = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; @@ -116,10 +114,7 @@ menuIconURI, blockIconURI, blocks: [ - { - blockType: Scratch.BlockType.LABEL, - text: "Text Blocks", - }, + { blockType: Scratch.BlockType.LABEL, text: "Text Blocks" }, { opcode: "askAndWait", blockType: Scratch.BlockType.COMMAND, @@ -152,10 +147,7 @@ blockType: Scratch.BlockType.COMMAND, text: "remove all ask boxes", }, - { - blockType: Scratch.BlockType.LABEL, - text: "Formatting", - }, + { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, { opcode: "setFontSize", blockType: Scratch.BlockType.COMMAND, @@ -239,9 +231,7 @@ }, }, }, - "---", - { opcode: "setButton", blockType: Scratch.BlockType.COMMAND, @@ -259,6 +249,12 @@ }, }, }, + { + opcode: "deleteAllButtons", + blockType: Scratch.BlockType.COMMAND, + text: "remove all buttons", + blockIconURI: formatIcon + }, { opcode: "setButtonText", blockType: Scratch.BlockType.COMMAND, @@ -276,10 +272,7 @@ }, }, }, - { - blockType: Scratch.BlockType.LABEL, - text: "Positioning", - }, + { blockType: Scratch.BlockType.LABEL, text: "Positioning" }, { opcode: "setPrePosition", blockType: Scratch.BlockType.COMMAND, @@ -370,10 +363,7 @@ text: "direction", blockIconURI: formatIcon, }, - { - blockType: Scratch.BlockType.LABEL, - text: "Visual Settings", - }, + { blockType: Scratch.BlockType.LABEL, text: "Visual Settings" }, { opcode: "setColorSettings", blockType: Scratch.BlockType.COMMAND, @@ -445,9 +435,7 @@ }, }, }, - "---", - { opcode: "enableShadow", blockType: Scratch.BlockType.COMMAND, @@ -478,9 +466,7 @@ }, }, }, - "---", - { opcode: "setBorderRadius", blockType: Scratch.BlockType.COMMAND, @@ -498,9 +484,7 @@ }, }, }, - "---", - { opcode: "setImage", blockType: Scratch.BlockType.COMMAND, @@ -535,10 +519,7 @@ }, }, }, - { - blockType: Scratch.BlockType.LABEL, - text: "Effects", - }, + { blockType: Scratch.BlockType.LABEL, text: "Effects" }, { opcode: "resetEffect", blockType: Scratch.BlockType.COMMAND, @@ -592,9 +573,7 @@ }, }, }, - "---", - { opcode: "setTimeout", blockType: Scratch.BlockType.COMMAND, @@ -613,10 +592,7 @@ text: "current textbox timeout", blockIconURI: effectIcon, }, - { - blockType: Scratch.BlockType.LABEL, - text: "Operations", - }, + { blockType: Scratch.BlockType.LABEL, text: "Operations" }, { opcode: "isWaitingInput", blockType: Scratch.BlockType.BOOLEAN, @@ -653,7 +629,7 @@ { opcode: "getBoxInfo", blockType: Scratch.BlockType.REPORTER, - text: "box [INFO]", + text: "textbox [INFO]", arguments: { INFO: { type: Scratch.ArgumentType.STRING, @@ -670,7 +646,7 @@ }, boxInfo: { acceptReporters: true, - items: ["count", "limit"], + items: ["count", "limit", "button count", "button names"], }, buttonType: { acceptReporters: true, @@ -756,23 +732,15 @@ value: i.family, })) : []; - return [ - ...fontMenu, - ...customFonts, - ]; + return [ ...fontMenu, ...customFonts ]; } allButtons(array, enableText) { const customButtons = Object.keys(this.buttonJSON); if (enableText) { - customButtons.forEach((button) => { - customButtons.push(button + " Text"); - }); + customButtons.forEach((button) => { customButtons.push(button + " Text") }); } - return [ - ...array, - ...customButtons, - ]; + return [ ...array, ...customButtons ]; } updateOverlayPos(overlay) { @@ -884,25 +852,17 @@ } } - showEffect(args) { - const effect = args.EFFECT; - return this[effect]; - } + showEffect(args) { return this[args.EFFECT] } setEffect(args) { - const effect = args.EFFECT; - this[effect] = args.AMT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this[args.EFFECT] = args.AMT; + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } resetEffect() { @@ -917,10 +877,7 @@ this.Scale = 100; this.SkewX = 0; this.SkewY = 0; - - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setColorSettings(args) { @@ -965,9 +922,7 @@ } break; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } findGradientType(menu) { @@ -1002,9 +957,7 @@ const buttonInfo = this.buttonJSON[newColorType[1]]; buttonInfo.color = gradientColor; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setCircleGradient(args) { @@ -1017,9 +970,7 @@ const buttonInfo = this.buttonJSON[newColorType[1]]; buttonInfo.color = gradientColor; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setBorderRadius(args) { @@ -1043,9 +994,7 @@ } break; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setShadow(args) { @@ -1064,9 +1013,7 @@ this.shadowS[3] = args.AMT / 100; break; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setImage(args) { @@ -1080,9 +1027,7 @@ const buttonInfo = this.buttonJSON[args.ELEMENT]; buttonInfo.image = args.IMAGE; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } scaleImage(args) { @@ -1096,25 +1041,19 @@ const buttonInfo = this.buttonJSON[args.ELEMENT]; buttonInfo.imgScale = args.SCALE; } - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setDirection(args) { const ROTATE = args.ROTATE; this.Rotation = Scratch.Cast.toNumber(ROTATE); - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } changeDirection(args) { const ROTATE = args.ROTATE; this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } reportDirection() { return this.Rotation } @@ -1127,17 +1066,13 @@ setPosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - this.activeOverlays.forEach((overlay) => { - this.updateOverlayPos(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay) }); } changePosition(args) { this.textBoxX = this.textBoxX + Scratch.Cast.toNumber(args.X) / (screen.width / 400); this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - this.activeOverlays.forEach((overlay) => { - this.updateOverlayPos(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay) }); } getXpos() { return this.textBoxX * (screen.width / 400) } @@ -1148,16 +1083,12 @@ setTextAlignment(args) { this.textAlign = args.ALIGNMENT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setFontFamily(args) { this.fontFamily = args.FONT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setSlider(args) { this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT] } @@ -1215,9 +1146,7 @@ askAndWaitForInput(args) { if (this.askBoxInfo[0] < this.askBoxInfo[1] ) { - return this.askAndWait(args).then(() => { - return this.getUserInput(); - }); + return this.askAndWait(args).then(() => { return this.getUserInput() }); } } @@ -1375,11 +1304,8 @@ const sliderContainer = document.createElement("div"); sliderContainer.classList.add("slider-container"); - const slider = document.createElement("input"); - if (this.isInputEnabled.includes("Vertical")) { - slider.style.transform = "rotate(270deg)"; - } + if (this.isInputEnabled.includes("Vertical")) slider.style.transform = "rotate(270deg)"; slider.type = "range"; slider.min = this.sliderInfo[0]; slider.max = this.sliderInfo[1]; @@ -1402,7 +1328,7 @@ valueDisplay.textContent = slider.value; slider.addEventListener("input", () => { valueDisplay.textContent = slider.value; - inputField.value = valueDisplay.textContent; + this.userInput = valueDisplay.textContent; }); overlay.appendChild(questionText); @@ -1498,6 +1424,11 @@ Scratch.vm.extensionManager.refreshBlocks() } + deleteAllButtons() { + this.buttonJSON = {}; + Scratch.vm.extensionManager.refreshBlocks() + } + isWaitingInput() { return this.isWaitingForInput } isDropdown() { return this.isDropdownOpen } @@ -1513,7 +1444,14 @@ getUserInput() { return this.userInput === null ? "" : this.userInput } - getBoxInfo(args) { return this.askBoxInfo[args.INFO === "count" ? 0 : 1] } + getBoxInfo(args) { + if (args.INFO.includes("button")) { + const buttons = Object.keys(this.buttonJSON); + return args.INFO.includes("names") ? JSON.stringify(buttons) : buttons.length; + } else { + return this.askBoxInfo[args.INFO === "count" ? 0 : 1] + } + } setSubmitEvent(args) { this.forceInput = args.ENTER } } From da5b473ab2bdac7a79626b6d81b083a956c0bf06 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Wed, 6 Dec 2023 14:35:06 -0800 Subject: [PATCH 24/46] Update Better-Input.svg --- images/SharkPool/Better-Input.svg | 122 +++++++++++++++--------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/images/SharkPool/Better-Input.svg b/images/SharkPool/Better-Input.svg index d9565362d3..25557244fe 100644 --- a/images/SharkPool/Better-Input.svg +++ b/images/SharkPool/Better-Input.svg @@ -1,65 +1,65 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 67e19d7ec9b14a67c0c929eec4454d8063f92e69 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Wed, 13 Dec 2023 21:26:26 -0800 Subject: [PATCH 25/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 149 ++++++++++------------------ 1 file changed, 51 insertions(+), 98 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index 8347da4aba..de6662ea52 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -3,11 +3,10 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.3.0.2 (Bug Fixes and New Blocks) +// Version V.3.1.0 (New Blocks and Input Types + Minor Changes) (function (Scratch) { "use strict"; - if (!Scratch.extensions.unsandboxed) throw new Error("Better Input must run unsandboxed"); const menuIconURI = @@ -28,13 +27,8 @@ let newColorType = ""; let overlayImageContainer = ""; const fontMenu = [ - "Scratch", - "Sans Serif", - "Serif", - "Handwriting", - "Marker", - "Curly", - "Pixel" + "Scratch", "Sans Serif", "Serif", + "Handwriting", "Marker", "Curly", "Pixel" ]; class BetterInputSP { @@ -45,6 +39,7 @@ this.isWaitingForInput = false; this.isDropdownOpen = false; this.userInput = " "; + this.defaultValue = ""; this.textBoxX = 0; this.textBoxY = 0; this.askBoxInfo = [0, 1]; @@ -65,19 +60,15 @@ this.buttonJSON = { "Submit": { borderRadius: 5, - color: "#0074D9", - textColor: "#ffffff", + color: "#0074D9", textColor: "#ffffff", name: "Submit", - image: "", - imgScale: 100, + image: "", imgScale: 100 }, "Cancel": { borderRadius: 5, - color: "#d9534f", - textColor: "#ffffff", + color: "#d9534f", textColor: "#ffffff", name: "Cancel", - image: "", - imgScale: 100, + image: "", imgScale: 100 }, }; @@ -142,6 +133,17 @@ blockType: Scratch.BlockType.REPORTER, text: "user input", }, + { + opcode: "setDefaultV", + blockType: Scratch.BlockType.COMMAND, + text: "set default value to [defaultV]", + arguments: { + defaultV: { + type: Scratch.ArgumentType.STRING, + defaultValue: "My Name Is...", + }, + }, + }, { opcode: "removeAskBoxes", blockType: Scratch.BlockType.COMMAND, @@ -169,7 +171,6 @@ ALIGNMENT: { type: Scratch.ArgumentType.STRING, menu: "alignmentMenu", - defaultValue: "left", }, }, }, @@ -182,7 +183,6 @@ FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu", - defaultValue: "Sans Serif", }, }, }, @@ -195,7 +195,6 @@ ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu", - defaultValue: "Text", }, }, }, @@ -241,7 +240,6 @@ BUTTON: { type: Scratch.ArgumentType.STRING, menu: "buttonType", - defaultValue: "add", }, NAME: { type: Scratch.ArgumentType.STRING, @@ -264,7 +262,6 @@ BUTTON_MENU: { type: Scratch.ArgumentType.STRING, menu: "buttonMenu", - defaultValue: "Dropdown", }, TEXT: { type: Scratch.ArgumentType.STRING, @@ -373,7 +370,6 @@ COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "colorSettingsMenu", - defaultValue: "Textbox", }, COLOR: { type: Scratch.ArgumentType.COLOR, @@ -390,7 +386,6 @@ COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu", - defaultValue: "Textbox", }, COLOR1: { type: Scratch.ArgumentType.COLOR, @@ -415,7 +410,6 @@ COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu", - defaultValue: "Textbox", }, COLOR1: { type: Scratch.ArgumentType.COLOR, @@ -445,7 +439,6 @@ ACTION: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu", - defaultValue: "Enabled", }, }, }, @@ -458,7 +451,6 @@ SHADOW: { type: Scratch.ArgumentType.STRING, menu: "shadowStuff", - defaultValue: "Size", }, AMT: { type: Scratch.ArgumentType.NUMBER, @@ -476,7 +468,6 @@ ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu", - defaultValue: "Textbox", }, VALUE: { type: Scratch.ArgumentType.NUMBER, @@ -494,7 +485,6 @@ ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu", - defaultValue: "Textbox", }, IMAGE: { type: Scratch.ArgumentType.STRING, @@ -511,7 +501,6 @@ ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu", - defaultValue: "Textbox", }, SCALE: { type: Scratch.ArgumentType.NUMBER, @@ -535,7 +524,6 @@ EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu", - defaultValue: "Blur", }, AMT: { type: Scratch.ArgumentType.NUMBER, @@ -552,7 +540,6 @@ EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu", - defaultValue: "Blur", }, AMT: { type: Scratch.ArgumentType.NUMBER, @@ -569,7 +556,6 @@ EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu", - defaultValue: "Blur", }, }, }, @@ -611,7 +597,6 @@ ENTER: { type: Scratch.ArgumentType.STRING, menu: "enterMenu", - defaultValue: "Disabled", }, }, }, @@ -634,12 +619,15 @@ INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo", - defaultValue: "count", }, }, }, ], menus: { + enableMenu: { + acceptReporters: true, + items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"], + }, alignmentMenu: { acceptReporters: true, items: ["left", "right", "center"], @@ -663,28 +651,19 @@ inputActionMenu: { acceptReporters: true, items: [ - "Text", - "None", - "Dropdown", - "Multi-Select Dropdown", - "Horizontal Slider", - "Vertical Slider" + "Text", "Number", + "None", "Color", + "Dropdown", "Multi-Select Dropdown", + "Horizontal Slider", "Vertical Slider" ], }, effectMenu: { acceptReporters: true, items: [ - "Blur", - "Brightness", - "Opacity", - "Invert", - "Saturation", - "Hue", - "Sepia", - "Contrast", - "Scale", - "SkewX", - "SkewY", + "Blur", "Brightness", + "Opacity", "Invert", "Saturation", + "Hue", "Sepia", "Contrast", + "Scale", "SkewX", "SkewY", ], }, shadowStuff: { @@ -708,13 +687,9 @@ colorSettingsMenu: { acceptReporters: true, items: this.allButtons([ - "Textbox", - "Question Text", - "Input Text", - "Input Box", - "Input Outline", - "Dropdown Button", - "Dropdown Text", + "Textbox", "Question Text", + "Input Text", "Input Box", "Input Outline", + "Dropdown Button", "Dropdown Text", ], true), }, enterMenu: { @@ -1136,12 +1111,9 @@ } }); this.askBoxPromises = []; - this.activeOverlays = this.activeOverlays.filter( - (overlay) => !overlaysToRemove.includes(overlay) - ); + this.activeOverlays = this.activeOverlays.filter((overlay) => !overlaysToRemove.includes(overlay)); this.activeUI = []; this.askBoxInfo[0] = 0; - this.userInput = ""; } askAndWaitForInput(args) { @@ -1154,7 +1126,6 @@ if (this.askBoxInfo[0] < this.askBoxInfo[1]) { const question = args.question; this.isWaitingForInput = true; - this.userInput = null; this.askBoxInfo[0]++; let selectedOptions = []; @@ -1179,20 +1150,11 @@ overlayImageContainer.style.zIndex = "-1"; if (this.forceInput !== "Disabled") { - let overlayInput; - if (this.forceInput === "Enter Key") { - overlayInput = "Enter"; - } else if (this.forceInput === "Shift + Enter Key") { - overlayInput = "ShiftEnter"; - } else { - overlayInput = this.forceInput; - } + let overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; const handleKeydown = (event) => { if ( - (overlayInput === "ShiftEnter" && - event.shiftKey && - event.key === "Enter") || - event.key === overlayInput + (overlayInput === "ShiftEnter" && event.shiftKey && + event.key === "Enter") || event.key === overlayInput ) { this.userInput = inputField.value; this.closeOverlay(overlay); @@ -1201,10 +1163,7 @@ }; const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { - if ( - mutation.type === "childList" && - !document.contains(overlay) - ) { + if (mutation.type === "childList" && !document.contains(overlay)) { document.removeEventListener("keydown", handleKeydown); observer.disconnect(); } @@ -1226,7 +1185,8 @@ inputField.style.padding = "5px"; inputField.style.fontSize = this.fontSize; inputField.style.margin = "0 auto"; - + inputField.type = this.isInputEnabled === "Color" ? "color" : this.isInputEnabled === "Number" ? "number" : "text"; + inputField.addEventListener("input", () => { this.userInput = inputField.value }); const buttonContainer = document.createElement("div"); buttonContainer.classList.add("button-container"); for (const buttonName in this.buttonJSON) { @@ -1244,11 +1204,7 @@ button.textContent = buttonInfo.name; button.style.display = "inline-block"; button.addEventListener("click", () => { - if (this.isInputEnabled === "Disabled") { - this.userInput = buttonInfo.name; - } else { - this.userInput = inputField.value; - } + this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; this.closeOverlay(overlay); resolve(); }); @@ -1258,7 +1214,6 @@ const dropdown = document.createElement("div"); dropdown.className = "dropdown"; - const dropdownButton = document.createElement("button"); dropdownButton.className = "dropbtn"; dropdownButton.textContent = this.DropdownText; @@ -1290,6 +1245,7 @@ } else { inputField.value = label; } + this.userInput = inputField.value; }); optionLabel.appendChild(optionRadio); optionLabel.appendChild(document.createTextNode(" " + label)); @@ -1333,7 +1289,7 @@ overlay.appendChild(questionText); if (this.isInputEnabled !== "Disabled") { - if (this.isInputEnabled === "Enabled") { + if (this.isInputEnabled === "Enabled" || this.isInputEnabled === "Color" || this.isInputEnabled === "Number") { overlay.appendChild(inputField); } else if (this.isInputEnabled.includes("Dropdown")) { overlay.appendChild(dropdownButton); @@ -1349,7 +1305,7 @@ overlay.appendChild(overlayImageContainer); document.body.appendChild(overlay); inputField.focus(); - + inputField.value = this.defaultValue; const resizeHandler = () => { if (this.textBoxX !== null && this.textBoxY !== null) { overlay.style.left = `${50 + this.textBoxX}%`; @@ -1359,14 +1315,9 @@ overlay.style.top = "50%"; } }; - this.activeOverlays.push(overlay); this.activeUI.push({ - overlay: { - button: buttonContainer, - dropdown: dropdownButton, - input: inputField, - }, + overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField }, }); document.addEventListener("fullscreenchange", resizeHandler); document.addEventListener("webkitfullscreenchange", resizeHandler); @@ -1416,17 +1367,17 @@ textColor: "#ffffff", name: args.NAME, image: "", - imgScale: 100, + imgScale: 100 }; } else { delete this.buttonJSON[args.NAME]; } - Scratch.vm.extensionManager.refreshBlocks() + Scratch.vm.extensionManager.refreshBlocks(); } deleteAllButtons() { this.buttonJSON = {}; - Scratch.vm.extensionManager.refreshBlocks() + Scratch.vm.extensionManager.refreshBlocks(); } isWaitingInput() { return this.isWaitingForInput } @@ -1454,6 +1405,8 @@ } setSubmitEvent(args) { this.forceInput = args.ENTER } + + setDefaultV(args) { this.defaultValue = args.defaultV } } Scratch.extensions.register(new BetterInputSP()); From 7dfac2df3229c353871f4204813391fb599789a8 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:40:36 -0800 Subject: [PATCH 26/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 301 +++++++++++----------------- 1 file changed, 119 insertions(+), 182 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index de6662ea52..f353e4cc89 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -3,7 +3,7 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.3.1.0 (New Blocks and Input Types + Minor Changes) +// Version V.3.1.1 (Bug Fixes + Code Optimization) (function (Scratch) { "use strict"; @@ -150,6 +150,34 @@ text: "remove all ask boxes", }, { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, + { + opcode: "setEnable", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: true, + text: "set [ENABLE_MENU] to be [ACTION]", + arguments: { + ENABLE_MENU: { + type: Scratch.ArgumentType.STRING, + menu: "enableMenu", + }, + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "inputActionMenu", + } + }, + }, + { + opcode: "getBoxCount", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, + text: "box count", + }, + { + opcode: "getMaxCount", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, + text: "box limit", + }, { opcode: "setFontSize", blockType: Scratch.BlockType.COMMAND, @@ -703,28 +731,22 @@ allFonts() { const customFonts = Scratch.vm.runtime.fontManager ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({ - text: i.name, - value: i.family, + text: i.name, value: i.family })) : []; return [ ...fontMenu, ...customFonts ]; } - allButtons(array, enableText) { - const customButtons = Object.keys(this.buttonJSON); - if (enableText) { - customButtons.forEach((button) => { customButtons.push(button + " Text") }); - } - return [ ...array, ...customButtons ]; + allButtons(array, enableTxt) { + const customBtn = Object.keys(this.buttonJSON); + if (enableTxt) customBtn.forEach((btn) => { customBtn.push(btn + " Text") }); + return [ ...array, ...customBtn ]; } updateOverlayPos(overlay) { if (this.Rotation > 359) { this.Rotation = 0; - } else if (this.Rotation < 1) { - this.Rotation = 360; - } - + } else if (this.Rotation < 1) { this.Rotation = 360 } if (this.textBoxX !== null && this.textBoxY !== null) { overlay.style.left = `${50 + this.textBoxX}%`; overlay.style.top = `${50 + this.textBoxY}%`; @@ -777,7 +799,6 @@ updateButtonImages(overlay) { let text = overlay.querySelector(".question"); if (text) text.style.color = this.questionColor; - const inputField = overlay.querySelector("input"); if (inputField) { inputField.style.background = ""; @@ -820,9 +841,7 @@ if (canFetch) { element.style.background = `url(${encodeURI(url)})`; element.style.backgroundSize = scale + "%"; - } else { - console.log("Cannot fetch content from the URL"); - } + } else { console.log("Cannot fetch content from the URL") } }); } } @@ -858,69 +877,41 @@ setColorSettings(args) { const colorType = args.COLOR_TYPE; const colorValue = args.COLOR; - switch (colorType) { - case "Question Text": - this.questionColor = colorValue; - break; - case "Input Text": - this.inputColor = colorValue; - break; - case "Textbox": - this.textBoxColor[0] = colorValue; - this.overlayImage[0] = " "; - break; - case "Input Box": - this.inputFieldColor[0] = colorValue; - this.overlayImage[1] = " "; - break; - case "Input Outline": - this.inputFieldColor[1] = colorValue; - break; - case "Dropdown Button": - this.dropdownButtonColor[0] = colorValue; - this.overlayImage[2] = " "; - break; - case "Dropdown Text": - this.dropdownButtonColor[1] = colorValue; - break; - default: - if (this.buttonJSON[colorType] || this.buttonJSON[colorType.replace(" Text", "")]) { - let buttonInfo; - if (colorType.includes(" Text")) { - buttonInfo = this.buttonJSON[colorType.replace(" Text", "")]; - buttonInfo.textColor = colorValue; - } else { - buttonInfo = this.buttonJSON[colorType]; - buttonInfo.color = colorValue; - buttonInfo.image = " "; - } - } - break; + const colorTypeMap = { + "Question Text": () => this.questionColor = colorValue, + "Input Text": () => this.inputColor = colorValue, + "Textbox": () => { this.textBoxColor[0] = colorValue; this.overlayImage[0] = " "; }, + "Input Box": () => { this.inputFieldColor[0] = colorValue; this.overlayImage[1] = " "; }, + "Input Outline": () => this.inputFieldColor[1] = colorValue, + "Dropdown Button": () => { this.dropdownButtonColor[0] = colorValue; this.overlayImage[2] = " "; }, + "Dropdown Text": () => this.dropdownButtonColor[1] = colorValue, + }; + const buttonInfo = this.buttonJSON[colorType] || this.buttonJSON[colorType.replace(" Text", "")]; + if (buttonInfo) { + if (colorType.includes(" Text")) { + buttonInfo.textColor = colorValue; + } else { + buttonInfo.color = colorValue; + buttonInfo.image = " "; + } } - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); + const applyColor = colorTypeMap[colorType]; + if (applyColor) applyColor(); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } findGradientType(menu) { - const colorType = menu; - switch (colorType) { - case "Textbox": - newColorType = "textBoxColor"; - this.overlayImage[0] = " "; - return newColorType; - case "Input Box": - newColorType = "inputFieldColor"; - this.overlayImage[1] = " "; - return newColorType; - case "Dropdown Button": - newColorType = "dropdownButtonColor"; - this.overlayImage[2] = " "; - return newColorType; - default: - if (this.buttonJSON[colorType]) { - newColorType = ["button", colorType]; - } - return newColorType; - } + const colorTypeMap = { + Textbox: { newColorType: "textBoxColor", ind: 0 }, + "Input Box": { newColorType: "inputFieldColor", ind: 1 }, + "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 } + }; + if (colorTypeMap[menu]) { + const { newColorType, ind } = colorTypeMap[menu]; + this.overlayImage[ind] = " "; + return newColorType; + } else if (this.buttonJSON[menu]) { return ["button", menu] } + return menu; } setGradient(args) { @@ -950,84 +941,56 @@ setBorderRadius(args) { const element = args.ELEMENT; - let value = args.VALUE; - if (value < 0) value = 0; - switch (element) { - case "Textbox": - this.overlayBorderRadius[0] = value; - break; - case "Input Box": - this.overlayBorderRadius[1] = value; - break; - case "Dropdown Button": - this.overlayBorderRadius[2] = value; - break; - default: - if (this.buttonJSON[element]) { - const buttonInfo = this.buttonJSON[element]; - buttonInfo.borderRadius = value; - } - break; + let value = Math.max(args.VALUE, 0); + const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; + const elementIndex = elementMap[element]; + if (elementIndex !== undefined) { + this.overlayBorderRadius[elementIndex] = value; + } else if (this.buttonJSON[element]) { + this.buttonJSON[element].borderRadius = value; } - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setShadow(args) { - const shadow = args.SHADOW; - switch (shadow) { - case "Size": - this.shadowS[2] = args.AMT; - break; - case "X": - this.shadowS[0] = args.AMT; - break; - case "Y": - this.shadowS[1] = args.AMT; - break; - case "Opacity": - this.shadowS[3] = args.AMT / 100; - break; + const shadowMap = { Size: 2, X: 0, Y: 1, Opacity: 3 }; + const propertyIndex = shadowMap[args.SHADOW]; + if (propertyIndex !== undefined) { + this.shadowS[propertyIndex] = args.AMT; + if (args.SHADOW === "Opacity") this.shadowS[propertyIndex] /= 100; } - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setImage(args) { - if (args.ELEMENT === "Textbox") { - this.overlayImage[0] = args.IMAGE; - } else if (args.ELEMENT === "Input Box") { - this.overlayImage[1] = args.IMAGE; - } else if (args.ELEMENT === "Dropdown Button") { - this.overlayImage[2] = args.IMAGE; + const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; + const elementIndex = elementMap[args.ELEMENT]; + if (elementIndex !== undefined) { + this.overlayImage[elementIndex] = args.IMAGE; } else if (this.buttonJSON[args.ELEMENT]) { - const buttonInfo = this.buttonJSON[args.ELEMENT]; - buttonInfo.image = args.IMAGE; + this.buttonJSON[args.ELEMENT].image = args.IMAGE; } - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } scaleImage(args) { - if (args.ELEMENT === "Textbox") { - this.imgScale[0] = args.SCALE; - } else if (args.ELEMENT === "Input Box") { - this.imgScale[1] = args.SCALE; - } else if (args.ELEMENT === "Dropdown Button") { - this.imgScale[2] = args.SCALE; + const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; + const elementIndex = elementMap[args.ELEMENT]; + if (elementIndex !== undefined) { + this.imgScale[elementIndex] = args.SCALE; } else if (this.buttonJSON[args.ELEMENT]) { - const buttonInfo = this.buttonJSON[args.ELEMENT]; - buttonInfo.imgScale = args.SCALE; + this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; } - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setDirection(args) { - const ROTATE = args.ROTATE; - this.Rotation = Scratch.Cast.toNumber(ROTATE); + this.Rotation = Scratch.Cast.toNumber(args.ROTATE); this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } changeDirection(args) { - const ROTATE = args.ROTATE; - this.Rotation = this.Rotation + Scratch.Cast.toNumber(ROTATE); + this.Rotation = this.Rotation + Scratch.Cast.toNumber(args.ROTATE); this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } @@ -1071,9 +1034,7 @@ setInputType(args) { if (args.ACTION === "Text" || args.ACTION === "None") { this.isInputEnabled = args.ACTION === "Text" ? "Enabled" : "Disabled"; - } else { - this.isInputEnabled = args.ACTION; - } + } else { this.isInputEnabled = args.ACTION } } enableShadow(args) { this.shadowEnabled = args.ACTION === "Enabled" } @@ -1093,9 +1054,7 @@ setDropdown(args) { try { this.optionList = JSON.parse(args.DROPDOWN); - } catch (error) { - this.optionList = ["Undefined Array Error"]; - } + } catch { this.optionList = ["Undefined Array Error"] } } removeAskBoxes() { @@ -1128,7 +1087,6 @@ this.isWaitingForInput = true; this.askBoxInfo[0]++; let selectedOptions = []; - return new Promise((resolve) => { const askBoxPromise = { resolve }; this.askBoxPromises.push(askBoxPromise); @@ -1148,14 +1106,10 @@ overlayImageContainer.style.top = 0; overlayImageContainer.style.left = 0; overlayImageContainer.style.zIndex = "-1"; - if (this.forceInput !== "Disabled") { - let overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; + const overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; const handleKeydown = (event) => { - if ( - (overlayInput === "ShiftEnter" && event.shiftKey && - event.key === "Enter") || event.key === overlayInput - ) { + if ((overlayInput === "ShiftEnter" && event.shiftKey && event.key === "Enter") || event.key === overlayInput) { this.userInput = inputField.value; this.closeOverlay(overlay); resolve(); @@ -1238,13 +1192,9 @@ if (this.isInputEnabled === "Multi-Select Dropdown") { if (selectedOptions.includes(label)) { selectedOptions = selectedOptions.filter(item => item !== label); - } else { - selectedOptions.push(label); - } + } else { selectedOptions.push(label) } inputField.value = selectedOptions.length > 0 ? JSON.stringify(selectedOptions) : ""; - } else { - inputField.value = label; - } + } else { inputField.value = label } this.userInput = inputField.value; }); optionLabel.appendChild(optionRadio); @@ -1274,9 +1224,7 @@ for (let i = 0; i < 4; i++) { sliderContainer.appendChild(document.createElement("br")); } - } else { - sliderContainer.appendChild(slider); - } + } else { sliderContainer.appendChild(slider) } const valueDisplay = document.createElement("span"); valueDisplay.classList.add("slider-value"); sliderContainer.appendChild(valueDisplay); @@ -1307,24 +1255,15 @@ inputField.focus(); inputField.value = this.defaultValue; const resizeHandler = () => { - if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${50 + this.textBoxX}%`; - overlay.style.top = `${50 + this.textBoxY}%`; - } else { - overlay.style.left = "50%"; - overlay.style.top = "50%"; - } + overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; + overlay.style.top = `${this.textBoxY !== null ? 50 + this.textBoxY : 50}%`; }; this.activeOverlays.push(overlay); - this.activeUI.push({ - overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField }, - }); + this.activeUI.push({ overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField } }); document.addEventListener("fullscreenchange", resizeHandler); document.addEventListener("webkitfullscreenchange", resizeHandler); document.addEventListener("mozfullscreenchange", resizeHandler); document.addEventListener("MSFullscreenChange", resizeHandler); - - const overlayParent = overlay.parentNode; const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === "childList" && mutation.removedNodes.contains(overlay)) { @@ -1336,7 +1275,7 @@ } } }); - observer.observe(overlayParent, { childList: true }); + observer.observe(overlay.parentNode, { childList: true }); document.body.appendChild(overlay); inputField.focus(); this.updateOverlay(overlay); @@ -1349,12 +1288,12 @@ this.isDropdownOpen = false; this.askBoxInfo[0]--; const index = this.activeOverlays.indexOf(overlay); - if (index !== -1) { - this.activeOverlays.splice(index, 1); - this.askBoxPromises.splice(index, 1); - } - delete this.activeUI[overlay]; setTimeout(() => { + if (index !== -1) { + this.activeOverlays.splice(index, 1); + this.askBoxPromises.splice(index, 1); + } + delete this.activeUI[overlay]; document.body.removeChild(overlay); }, this.Timeout * 1000); } @@ -1363,15 +1302,11 @@ if (args.BUTTON === "add") { this.buttonJSON[args.NAME] = { borderRadius: 5, - color: "#0074D9", - textColor: "#ffffff", + color: "#0074D9", textColor: "#ffffff", name: args.NAME, - image: "", - imgScale: 100 + image: "", imgScale: 100 }; - } else { - delete this.buttonJSON[args.NAME]; - } + } else { delete this.buttonJSON[args.NAME] } Scratch.vm.extensionManager.refreshBlocks(); } @@ -1399,14 +1334,16 @@ if (args.INFO.includes("button")) { const buttons = Object.keys(this.buttonJSON); return args.INFO.includes("names") ? JSON.stringify(buttons) : buttons.length; - } else { - return this.askBoxInfo[args.INFO === "count" ? 0 : 1] - } + } else { return this.askBoxInfo[args.INFO === "count" ? 0 : 1] } } setSubmitEvent(args) { this.forceInput = args.ENTER } setDefaultV(args) { this.defaultValue = args.defaultV } + + setEnable() { throw new Error("This block is removed in Better Input V3. Please use the more powerful and better blocks") } + getBoxCount() { throw new Error("This block is removed in Better Input V3. Please use the more powerful and better blocks") } + getMaxCount() { throw new Error("This block is removed in Better Input V3. Please use the more powerful and better blocks") } } Scratch.extensions.register(new BetterInputSP()); From b1b41eb170f0f0d8466d66e2dd7739eece2eeba1 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 28 Jan 2024 22:13:07 -0800 Subject: [PATCH 27/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 990 ++++++++++++++-------------- 1 file changed, 479 insertions(+), 511 deletions(-) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index f353e4cc89..effa75ddd4 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -3,7 +3,7 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.3.1.1 (Bug Fixes + Code Optimization) +// Version V.4.0.0 (function (Scratch) { "use strict"; @@ -33,18 +33,14 @@ class BetterInputSP { constructor() { - this.activeOverlays = []; - this.activeUI = []; - this.askBoxPromises = []; - this.isWaitingForInput = false; - this.isDropdownOpen = false; - this.userInput = " "; - this.defaultValue = ""; - this.textBoxX = 0; - this.textBoxY = 0; - this.askBoxInfo = [0, 1]; + this.activeOverlays = []; this.activeUI = []; this.askBoxPromises = []; + this.isWaitingForInput = false; this.isDropdownOpen = false; + this.userInput = " "; this.defaultValue = ""; + this.textBoxX = 0; this.textBoxY = 0; + this.askBoxInfo = [0, 1]; this.appendTarget = ["window", false]; this.forceInput = "Disabled"; this.overlayInput = null; + this.uiOrder = ["question", "input", "buttons"]; this.optionList = ["Option 1", "Option 2", "Option 3"]; this.sliderInfo = [0, 100, 50]; @@ -56,43 +52,42 @@ this.fontSize = "14px"; this.textAlign = "left"; this.fontFamily = "Sans Serif"; - this.overlayBorderRadius = [5, 4, 5]; + // overlay + Image, input, dropdown button + this.mainUIinfo = [ + 5, 4, 5, + "1px none #000000", "1px solid #000000", "1px none #000000", + "15px", "5px", "5px 10px", + "none", "none", "none", ["", 0], ["", 0], ["", 0] + ]; + this.lastPressBtn = ""; this.buttonJSON = { "Submit": { - borderRadius: 5, color: "#0074D9", textColor: "#ffffff", - name: "Submit", - image: "", imgScale: 100 + name: "Submit", image: "", imgScale: 100, + borderRadius: 5, border: "1px none #000000", + padding: "5px 10px", dropShadow: "none", outline: ["", 0] }, "Cancel": { - borderRadius: 5, color: "#d9534f", textColor: "#ffffff", - name: "Cancel", - image: "", imgScale: 100 + name: "Cancel", image: "", imgScale: 100, + borderRadius: 5, border: "1px none #000000", + padding: "5px 10px", dropShadow: "none", outline: ["", 0] }, }; this.questionColor = "#000000"; this.inputColor = "#000000"; this.textBoxColor = ["#ffffff"]; - this.inputFieldColor = ["#ffffff", "#000000"]; + this.inputFieldColor = "#ffffff"; this.dropdownButtonColor = ["#5f5f5f", "#ffffff"]; this.overlayImage = [" ", " ", " "]; - this.Blur = 0; - this.Brightness = 0; - this.Opacity = 100; - this.Invert = 0; - this.Saturation = 100; - this.Hue = 0; - this.Sepia = 0; - this.Contrast = 100; - this.Scale = 100; - this.SkewX = 0; - this.SkewY = 0; - this.Rotation = 90; + this.Blur = 0; this.Brightness = 0; this.Opacity = 100; + this.Invert = 0; this.Saturation = 100; this.Hue = 0; + this.Sepia = 0; this.Contrast = 100; this.Scale = 100; + this.SkewX = 0; this.SkewY = 0; this.Rotation = 90; this.imgScale = [100, 100, 100]; - this.shadowS = [0, 0, 5, 0.3]; + this.shadowS = [0, 0, 5, "#000000"]; } getInfo() { @@ -100,21 +95,17 @@ id: "BetterInputSP", name: "Better Input", color1: "#9400ff", - color2: "#7600cc", - color3: "#8500e6", + color2: "#7800cd", + color3: "#6900b3", menuIconURI, blockIconURI, blocks: [ - { blockType: Scratch.BlockType.LABEL, text: "Text Blocks" }, { opcode: "askAndWait", blockType: Scratch.BlockType.COMMAND, text: "ask [question] and wait", arguments: { - question: { - type: Scratch.ArgumentType.STRING, - defaultValue: "What is your name?", - }, + question: { type: Scratch.ArgumentType.STRING, defaultValue: "What is your name?" } }, }, { @@ -122,61 +113,41 @@ blockType: Scratch.BlockType.REPORTER, text: "ask [question] and wait", arguments: { - question: { - type: Scratch.ArgumentType.STRING, - defaultValue: "What is your name?", - }, + question: { type: Scratch.ArgumentType.STRING, defaultValue: "What is your name?" } }, }, { - opcode: "getUserInput", - blockType: Scratch.BlockType.REPORTER, - text: "user input", + opcode: "getUserInput", blockType: Scratch.BlockType.REPORTER, + text: "user input" }, { opcode: "setDefaultV", blockType: Scratch.BlockType.COMMAND, text: "set default value to [defaultV]", arguments: { - defaultV: { - type: Scratch.ArgumentType.STRING, - defaultValue: "My Name Is...", - }, + defaultV: { type: Scratch.ArgumentType.STRING, defaultValue: "My Name Is..." } }, }, { - opcode: "removeAskBoxes", - blockType: Scratch.BlockType.COMMAND, - text: "remove all ask boxes", + opcode: "removeAskBoxes", blockType: Scratch.BlockType.COMMAND, + text: "remove all ask boxes" }, { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, { - opcode: "setEnable", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: true, - text: "set [ENABLE_MENU] to be [ACTION]", + opcode: "setEnable", blockType: Scratch.BlockType.COMMAND, + hideFromPalette: true, text: "set [ENABLE_MENU] to be [ACTION]", arguments: { - ENABLE_MENU: { - type: Scratch.ArgumentType.STRING, - menu: "enableMenu", - }, - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: "inputActionMenu", - } + ENABLE_MENU: { type: Scratch.ArgumentType.STRING, menu: "enableMenu" }, + ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } }, }, { - opcode: "getBoxCount", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, - text: "box count", + opcode: "getBoxCount", blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, text: "box count" }, { - opcode: "getMaxCount", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, - text: "box limit", + opcode: "getMaxCount", blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, text: "box limit" }, { opcode: "setFontSize", @@ -184,10 +155,7 @@ text: "set font size to [SIZE]", blockIconURI: formatIcon, arguments: { - SIZE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 14, - }, + SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 14 } }, }, { @@ -196,10 +164,7 @@ text: "set alignment to [ALIGNMENT]", blockIconURI: formatIcon, arguments: { - ALIGNMENT: { - type: Scratch.ArgumentType.STRING, - menu: "alignmentMenu", - }, + ALIGNMENT: { type: Scratch.ArgumentType.STRING, menu: "alignmentMenu" } }, }, { @@ -208,22 +173,39 @@ text: "set font to [FONT]", blockIconURI: formatIcon, arguments: { - FONT: { - type: Scratch.ArgumentType.STRING, - menu: "fontMenu", - }, + FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu" } }, }, + { + opcode: "setDropShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] shadow to x [x] y [y] z [z] color [COLOR]", + arguments: { + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, + x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 2 }, + COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" } + }, + }, + { + opcode: "setOutline", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] outline to [COLOR] thickness [THICK]", + arguments: { + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, + COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" }, + THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } + }, + }, + "---", { opcode: "setInputType", blockType: Scratch.BlockType.COMMAND, text: "set Input Box to be [ACTION]", blockIconURI: formatIcon, arguments: { - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: "inputActionMenu", - }, + ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } }, }, { @@ -232,10 +214,7 @@ text: "set dropdown options to array: [DROPDOWN]", blockIconURI: formatIcon, arguments: { - DROPDOWN: { - type: Scratch.ArgumentType.STRING, - defaultValue: "[\"Option 1\", \"Option 2\", \"Option 3\"]", - }, + DROPDOWN: { type: Scratch.ArgumentType.STRING, defaultValue: "[\"Option 1\", \"Option 2\", \"Option 3\"]" } }, }, { @@ -244,42 +223,25 @@ text: "set slider to min: [MIN] max: [MAX] default: [DEFAULT]", blockIconURI: formatIcon, arguments: { - MIN: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - MAX: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 100, - }, - DEFAULT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 50, - }, + MIN: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, + DEFAULT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 } }, }, - "---", + { blockType: Scratch.BlockType.LABEL, text: "Buttons" }, { opcode: "setButton", blockType: Scratch.BlockType.COMMAND, text: "[BUTTON] button named [NAME]", blockIconURI: formatIcon, arguments: { - BUTTON: { - type: Scratch.ArgumentType.STRING, - menu: "buttonType", - }, - NAME: { - type: Scratch.ArgumentType.STRING, - defaultValue: "Submit", - }, + BUTTON: { type: Scratch.ArgumentType.STRING, menu: "buttonType" }, + NAME: { type: Scratch.ArgumentType.STRING, defaultValue: "Submit" } }, }, { - opcode: "deleteAllButtons", - blockType: Scratch.BlockType.COMMAND, - text: "remove all buttons", - blockIconURI: formatIcon + opcode: "deleteAllButtons", blockType: Scratch.BlockType.COMMAND, + text: "remove all buttons", blockIconURI: formatIcon }, { opcode: "setButtonText", @@ -287,16 +249,14 @@ text: "set [BUTTON_MENU] button name to [TEXT]", blockIconURI: formatIcon, arguments: { - BUTTON_MENU: { - type: Scratch.ArgumentType.STRING, - menu: "buttonMenu", - }, - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: "my dropdown", - }, + BUTTON_MENU: { type: Scratch.ArgumentType.STRING, menu: "buttonMenu" }, + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "my dropdown" } }, }, + { + opcode: "lastButton", blockType: Scratch.BlockType.REPORTER, + text: "last pressed button", blockIconURI: formatIcon + }, { blockType: Scratch.BlockType.LABEL, text: "Positioning" }, { opcode: "setPrePosition", @@ -304,14 +264,8 @@ text: "preset textbox position to x: [X] y: [Y]", blockIconURI: formatIcon, arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, + X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }, }, { @@ -320,14 +274,8 @@ text: "set textbox position to x: [X] y: [Y]", blockIconURI: formatIcon, arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, + X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }, }, { @@ -336,27 +284,17 @@ text: "change textbox position by x: [X] y: [Y]", blockIconURI: formatIcon, arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, + X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }, }, { - opcode: "getXpos", - blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, - text: "x position", + opcode: "getXpos", blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, text: "x position" }, { - opcode: "getYpos", - blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, - text: "y position", + opcode: "getYpos", blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, text: "y position" }, { opcode: "setDirection", @@ -364,10 +302,7 @@ text: "set direction to [ROTATE]", blockIconURI: formatIcon, arguments: { - ROTATE: { - type: Scratch.ArgumentType.ANGLE, - defaultValue: 90, - }, + ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 90 } }, }, { @@ -376,17 +311,12 @@ text: "change direction by [ROTATE]", blockIconURI: formatIcon, arguments: { - ROTATE: { - type: Scratch.ArgumentType.ANGLE, - defaultValue: 15, - }, + ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 15 } }, }, { - opcode: "reportDirection", - blockType: Scratch.BlockType.REPORTER, - text: "direction", - blockIconURI: formatIcon, + opcode: "reportDirection", blockType: Scratch.BlockType.REPORTER, + text: "direction", blockIconURI: formatIcon }, { blockType: Scratch.BlockType.LABEL, text: "Visual Settings" }, { @@ -395,66 +325,49 @@ text: "set [COLOR_TYPE] color to [COLOR]", blockIconURI: colorIcon, arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "colorSettingsMenu", - }, - COLOR: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#000000", - }, + COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "colorSettingsMenu" }, + COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#000000" } + }, + }, + { + opcode: "setGradient", blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to gradient with [COLOR1] and [COLOR2] with direction [DIR]", + hideFromPalette: true, //deprecated but needed for support + arguments: { + COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, + DIR: { type: Scratch.ArgumentType.ANGLE } + }, + }, + { + opcode: "setCircleGradient", blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to radial gradient with [COLOR1] and [COLOR2] at x [X] y [Y]", + hideFromPalette: true, //deprecated but needed for support + arguments: { + COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, + X: { type: Scratch.ArgumentType.NUMBER }, Y: { type: Scratch.ArgumentType.NUMBER } }, }, + "---", { - opcode: "setGradient", + opcode: "setImage", blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to gradient with colors [COLOR1] and [COLOR2] with direction [DIR]", + text: "set [ELEMENT] image to [IMAGE]", blockIconURI: colorIcon, arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - COLOR1: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#ffffff", - }, - COLOR2: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#ff0000", - }, - DIR: { - type: Scratch.ArgumentType.ANGLE, - defaultValue: 90, - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + IMAGE: { type: Scratch.ArgumentType.STRING, defaultValue: "input-url-here" } }, }, { - opcode: "setCircleGradient", + opcode: "scaleImage", blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to radial gradient with colors [COLOR1] and [COLOR2] with position x [X] y [Y]", + text: "scale [ELEMENT] image to [SCALE]%", blockIconURI: colorIcon, arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - COLOR1: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#ffffff", - }, - COLOR2: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#ff0000", - }, - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0, - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + SCALE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 } }, }, "---", @@ -464,10 +377,7 @@ text: "set box shadow to be [ACTION]", blockIconURI: colorIcon, arguments: { - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: "buttonActionMenu", - }, + ACTION: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } }, }, { @@ -476,64 +386,44 @@ text: "set box shadow [SHADOW] to [AMT]", blockIconURI: colorIcon, arguments: { - SHADOW: { - type: Scratch.ArgumentType.STRING, - menu: "shadowStuff", - }, - AMT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, - }, + SHADOW: { type: Scratch.ArgumentType.STRING, menu: "shadowStuff" }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, "---", { - opcode: "setBorderRadius", + opcode: "setBorder", blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] border radius to [VALUE]", + text: "set [ELEMENT] border to [TYPE] color [COLOR] width [WIDTH]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - VALUE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + TYPE: { type: Scratch.ArgumentType.STRING, menu: "borderTypes" }, + COLOR: { type: Scratch.ArgumentType.COLOR }, + WIDTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, }, }, - "---", { - opcode: "setImage", + opcode: "setBorderRadius", blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] image to [IMAGE]", + text: "set [ELEMENT] border radius to [VALUE]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - IMAGE: { - type: Scratch.ArgumentType.STRING, - defaultValue: "input-url-or-uri-here", - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + VALUE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, }, }, { - opcode: "scaleImage", + opcode: "setPadding", blockType: Scratch.BlockType.COMMAND, - text: "scale [ELEMENT] image to [SCALE]%", + text: "set [ELEMENT] padding to T: [N1] B: [N3] L: [N4] R: [N2]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - SCALE: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 100, - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + N1: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N2: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N3: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N4: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, { blockType: Scratch.BlockType.LABEL, text: "Effects" }, @@ -541,7 +431,7 @@ opcode: "resetEffect", blockType: Scratch.BlockType.COMMAND, text: "reset effects", - blockIconURI: effectIcon, + blockIconURI: effectIcon }, { opcode: "setEffect", @@ -549,14 +439,8 @@ text: "set effect [EFFECT] to [AMT]", blockIconURI: effectIcon, arguments: { - EFFECT: { - type: Scratch.ArgumentType.STRING, - menu: "effectMenu", - }, - AMT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, - }, + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, }, }, { @@ -565,14 +449,8 @@ text: "change effect [EFFECT] by [AMT]", blockIconURI: effectIcon, arguments: { - EFFECT: { - type: Scratch.ArgumentType.STRING, - menu: "effectMenu", - }, - AMT: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, - }, + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, { @@ -581,10 +459,7 @@ text: "effect [EFFECT]", blockIconURI: effectIcon, arguments: { - EFFECT: { - type: Scratch.ArgumentType.STRING, - menu: "effectMenu", - }, + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" } }, }, "---", @@ -594,38 +469,63 @@ text: "when submitted delete textbox after [TIME] secs", blockIconURI: effectIcon, arguments: { - TIME: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5, - }, + TIME: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, { opcode: "reportTimeout", blockType: Scratch.BlockType.REPORTER, text: "current textbox timeout", - blockIconURI: effectIcon, + blockIconURI: effectIcon }, { blockType: Scratch.BlockType.LABEL, text: "Operations" }, + { + opcode: "setUI", + blockType: Scratch.BlockType.COMMAND, + text: "set UI order to [ARRAY]", + arguments: { + ARRAY: { type: Scratch.ArgumentType.STRING, defaultValue: "[\"question\", \"input\", \"buttons\"]" } + }, + }, + { + opcode: "getUIOrder", + blockType: Scratch.BlockType.REPORTER, + text: "UI order" + }, + "---", + { + opcode: "setAppend", + blockType: Scratch.BlockType.COMMAND, + text: "append next textbox to [TARGET]", + arguments: { + TARGET: { type: Scratch.ArgumentType.STRING, menu: "appendMenu" } + }, + }, + { + opcode: "setFocus", + blockType: Scratch.BlockType.COMMAND, + text: "toggle focus mode to [TYPE]", + arguments: { + TYPE: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } + }, + }, + "---", { opcode: "isWaitingInput", blockType: Scratch.BlockType.BOOLEAN, - text: "is waiting?", + text: "is waiting?" }, { opcode: "isDropdown", blockType: Scratch.BlockType.BOOLEAN, - text: "is dropdown open?", + text: "is dropdown open?" }, { opcode: "setSubmitEvent", blockType: Scratch.BlockType.COMMAND, text: "set force input to [ENTER]", arguments: { - ENTER: { - type: Scratch.ArgumentType.STRING, - menu: "enterMenu", - }, + ENTER: { type: Scratch.ArgumentType.STRING, menu: "enterMenu" } }, }, { @@ -633,10 +533,7 @@ blockType: Scratch.BlockType.COMMAND, text: "set max box count to: [MAX]", arguments: { - MAX: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1, - }, + MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 } }, }, { @@ -644,43 +541,47 @@ blockType: Scratch.BlockType.REPORTER, text: "textbox [INFO]", arguments: { - INFO: { - type: Scratch.ArgumentType.STRING, - menu: "boxInfo", - }, + INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo" } }, }, ], menus: { - enableMenu: { - acceptReporters: true, - items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"], - }, - alignmentMenu: { + enableMenu: { acceptReporters: true, items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"] }, + // ^ Old Menu ^ (Needed for V2 Support) + fontMenu: { acceptReporters: true, items: "allFonts" }, + buttonMenu: { acceptReporters: true, - items: ["left", "right", "center"], + items: this.allButtons(["Dropdown"], false), }, - boxInfo: { + elementMenu: { acceptReporters: true, - items: ["count", "limit", "button count", "button names"], + items: this.allButtons(["Textbox", "Input Box", "Dropdown Button"], false), }, - buttonType: { + colorSettingsMenu: { acceptReporters: true, - items: ["add", "remove"], + items: this.allButtons([ + "Textbox", "Question Text", "Textbox Shadow", + "Input Text", "Input Box", + "Dropdown Button", "Dropdown Text" + ], true), }, - fontMenu: { + textsMenu: { acceptReporters: true, - items: "allFonts", + items: this.allButtons(["Question Text", "Input Text", "Dropdown Text"], true, true), }, - buttonActionMenu: { + appendMenu: ["window", "canvas"], + buttonType: { acceptReporters: true, items: ["add", "remove"] }, + buttonActionMenu: { acceptReporters: true, items: ["Enabled", "Disabled"] }, + alignmentMenu: { acceptReporters: true, items: ["left", "right", "center"] }, + shadowStuff: { acceptReporters: true, items: ["Size", "X", "Y"] }, + boxInfo: { acceptReporters: true, - items: ["Enabled", "Disabled"], + items: ["count", "limit", "button count", "button names"], }, inputActionMenu: { acceptReporters: true, items: [ - "Text", "Number", - "None", "Color", + "None", "Text", "Password", "Number", "Color", "Dropdown", "Multi-Select Dropdown", "Horizontal Slider", "Vertical Slider" ], @@ -688,42 +589,23 @@ effectMenu: { acceptReporters: true, items: [ - "Blur", "Brightness", - "Opacity", "Invert", "Saturation", - "Hue", "Sepia", "Contrast", + "Blur", "Brightness", "Opacity", + "Invert", "Saturation", "Hue", + "Sepia", "Contrast", "Scale", "SkewX", "SkewY", ], }, - shadowStuff: { - acceptReporters: true, - items: ["Size", "X", "Y", "Opacity"], - }, - buttonMenu: { - acceptReporters: true, - items: this.allButtons([ - "Dropdown" - ], false), - }, - elementMenu: { - acceptReporters: true, - items: this.allButtons([ - "Textbox", - "Input Box", - "Dropdown Button", - ], false), - }, - colorSettingsMenu: { - acceptReporters: true, - items: this.allButtons([ - "Textbox", "Question Text", - "Input Text", "Input Box", "Input Outline", - "Dropdown Button", "Dropdown Text", - ], true), - }, enterMenu: { acceptReporters: true, items: ["Disabled", "Enter Key", "Shift + Enter Key"], }, + borderTypes: { + acceptReporters: true, + items: [ + "none", "solid", "dotted", "dashed", + "double", "groove", "ridge", "inset", "outset" + ], + } }, }; } @@ -737,87 +619,94 @@ return [ ...fontMenu, ...customFonts ]; } - allButtons(array, enableTxt) { - const customBtn = Object.keys(this.buttonJSON); - if (enableTxt) customBtn.forEach((btn) => { customBtn.push(btn + " Text") }); + allButtons(array, enableTxt, justTxt) { + let customBtn = Object.keys(this.buttonJSON); + if (justTxt) customBtn = customBtn.map(btn => btn + " Text"); + else if (enableTxt) customBtn.forEach((btn) => { customBtn.push(btn + " Text") }); return [ ...array, ...customBtn ]; } updateOverlayPos(overlay) { - if (this.Rotation > 359) { - this.Rotation = 0; - } else if (this.Rotation < 1) { this.Rotation = 360 } + if (this.Rotation > 359) this.Rotation = 0; + else if (this.Rotation < 1) this.Rotation = 360; if (this.textBoxX !== null && this.textBoxY !== null) { - overlay.style.left = `${50 + this.textBoxX}%`; - overlay.style.top = `${50 + this.textBoxY}%`; + if (this.appendTarget[0] === "window") { + overlay.style.left = `${50 + this.textBoxX}%`; + overlay.style.top = `${50 + this.textBoxY}%`; + } overlay.style.transform = ` - translate(-50%, -50%) - SkewX(${this.SkewX}deg) - SkewY(${this.SkewY}deg) - rotate(${this.Rotation - 90}deg) - scale(${this.Scale / 100}) + translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)` } + SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) `; } else { overlay.style.left = "50%"; overlay.style.top = "50%"; } } - updateOverlay(overlay) { const newOpacity = this.Opacity / 100; const newBrightness = this.Brightness + 100; overlay.style.backgroundImage = ""; overlay.style[this.textBoxColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.textBoxColor[0]; - overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px rgba(0, 0, 0, ${this.shadowS[3]})` : "none"; - + overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px ${this.shadowS[3]}` : "none"; overlay.style.transform = ` - translate(-50%, -50%) - SkewX(${this.SkewX}deg) - SkewY(${this.SkewY}deg) - rotate(${this.Rotation - 90}deg) - scale(${this.Scale / 100}) + translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)` } + SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) `; overlay.style.filter = ` - blur(${this.Blur}px) - brightness(${newBrightness}%) - invert(${this.Invert}%) - saturate(${this.Saturation}%) - hue-rotate(${this.Hue}deg) - sepia(${this.Sepia}%) + blur(${this.Blur}px) brightness(${newBrightness}%) + invert(${this.Invert}%) saturate(${this.Saturation}%) + hue-rotate(${this.Hue}deg) sepia(${this.Sepia}%) contrast(${this.Contrast}%) `; overlay.style.opacity = newOpacity; + overlay.style.border = this.mainUIinfo[3]; + overlay.style.padding = this.mainUIinfo[6]; overlay.style.fontFamily = this.fontFamily; overlay.style.textAlign = this.textAlign; - overlay.style.borderRadius = this.overlayBorderRadius[0] + "px"; - overlayImageContainer.style.borderRadius = this.overlayBorderRadius[0] + "px"; + overlay.style.borderRadius = `${this.mainUIinfo[0]}px`; + overlayImageContainer.style.borderRadius = `${this.mainUIinfo[0]}px`; overlayImageContainer.style.background = ""; this.setImageStyles(overlayImageContainer, this.overlayImage[0], this.imgScale[0]); this.updateButtonImages(overlay); } - updateButtonImages(overlay) { let text = overlay.querySelector(".question"); - if (text) text.style.color = this.questionColor; + if (text) { + text.style.color = this.questionColor; + text.style.textShadow = this.mainUIinfo[9]; + this.tryOutline(text, this.mainUIinfo[12][0], this.mainUIinfo[12][1]); + } const inputField = overlay.querySelector("input"); if (inputField) { + inputField.style.width = this.isInputEnabled === "Color" ? "100%" : "auto"; inputField.style.background = ""; - inputField.style[this.inputFieldColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.inputFieldColor[0]; + inputField.style.fontFamily = this.fontFamily; + inputField.style[this.inputFieldColor.includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.inputFieldColor; inputField.style.color = this.inputColor; - inputField.style.border = `1px solid ${this.inputFieldColor[1]}`; - inputField.style.borderRadius = this.overlayBorderRadius[1] + "px"; + inputField.style.textShadow = this.mainUIinfo[10]; + this.tryOutline(inputField, this.mainUIinfo[13][0], this.mainUIinfo[13][1]); + inputField.style.border = this.mainUIinfo[4]; + inputField.style.borderRadius = `${this.mainUIinfo[1]}px`; + inputField.style.padding = this.mainUIinfo[7]; this.setImageStyles(inputField, this.overlayImage[1], this.imgScale[1]); } - const dropdownButton = overlay.querySelector("button.dropbtn"); - if (dropdownButton) { - dropdownButton.style.backgroundImage = ""; - dropdownButton.style.color = this.dropdownButtonColor[1]; - dropdownButton.style.borderRadius = this.overlayBorderRadius[2] + "px"; - dropdownButton.style[this.dropdownButtonColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdownButtonColor[0]; - this.setImageStyles(dropdownButton, this.overlayImage[2], this.imgScale[2]); + const dropBtn = overlay.querySelector("button.dropbtn"); + if (dropBtn) { + dropBtn.style.backgroundImage = ""; + dropBtn.style.fontFamily = this.fontFamily; + dropBtn.style.color = this.dropdownButtonColor[1]; + dropBtn.style.borderRadius = `${this.mainUIinfo[2]}px`; + dropBtn.style.border = this.mainUIinfo[5]; + dropBtn.style.padding = this.mainUIinfo[8]; + dropBtn.style.textShadow = this.mainUIinfo[11]; + this.tryOutline(dropBtn, this.mainUIinfo[14][0], this.mainUIinfo[14][1]); + dropBtn.style[this.dropdownButtonColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdownButtonColor[0]; + this.setImageStyles(dropBtn, this.overlayImage[2], this.imgScale[2]); } - const buttonContainer = overlay.querySelector(".button-container"); if (buttonContainer) { const buttons = buttonContainer.querySelectorAll("button"); @@ -826,7 +715,12 @@ const buttonInfo = this.buttonJSON[buttonName]; if (buttonInfo) { button.style.color = buttonInfo.textColor; - button.style.borderRadius = buttonInfo.borderRadius + "px"; + button.style.fontFamily = this.fontFamily; + button.style.borderRadius = `${buttonInfo.borderRadius}px`; + button.style.border = buttonInfo.border; + button.style.padding = buttonInfo.padding; + button.style.textShadow = buttonInfo.dropShadow; + this.tryOutline(button, buttonInfo.outline[0], buttonInfo.outline[1]); button.style.background = ""; button.style[buttonInfo.color.includes("gradient") ? "backgroundImage" : "background"] = buttonInfo.color; this.setImageStyles(button, buttonInfo.image, buttonInfo.imgScale); @@ -834,13 +728,22 @@ }); } } + tryOutline(element, color, thick) { + element.style.webkitTextStrokeColor = color; + element.style.webkitTextStrokeWidth = `${thick}px`; + //multi-platform support cuz we cant have nice things + element.style.textStrokeColor = color; + element.style.textStrokeWidth = `${thick}px`; + element.style.mozTextStrokeColor = color; + element.style.mozTextStrokeWidth = `${thick}px`; + } setImageStyles(element, url, scale) { if (Scratch.Cast.toString(url).length > 5) { Scratch.canFetch(encodeURI(url)).then((canFetch) => { if (canFetch) { element.style.background = `url(${encodeURI(url)})`; - element.style.backgroundSize = scale + "%"; + element.style.backgroundSize = `${scale}%`; } else { console.log("Cannot fetch content from the URL") } }); } @@ -860,17 +763,9 @@ } resetEffect() { - this.Blur = 0; - this.Brightness = 0; - this.Opacity = 100; - this.Invert = 0; - this.Saturation = 100; - this.Hue = 0; - this.Sepia = 0; - this.Contrast = 100; - this.Scale = 100; - this.SkewX = 0; - this.SkewY = 0; + this.Blur = 0; this.Brightness = 0; this.Opacity = 100; this.Invert = 0; + this.Saturation = 100; this.Hue = 0; this.Sepia = 0; this.Contrast = 100; + this.Scale = 100; this.SkewX = 0; this.SkewY = 0; this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } @@ -881,8 +776,8 @@ "Question Text": () => this.questionColor = colorValue, "Input Text": () => this.inputColor = colorValue, "Textbox": () => { this.textBoxColor[0] = colorValue; this.overlayImage[0] = " "; }, - "Input Box": () => { this.inputFieldColor[0] = colorValue; this.overlayImage[1] = " "; }, - "Input Outline": () => this.inputFieldColor[1] = colorValue, + "Textbox Shadow": () => { this.shadowS[3] = colorValue }, + "Input Box": () => { this.inputFieldColor = colorValue; this.overlayImage[1] = " "; }, "Dropdown Button": () => { this.dropdownButtonColor[0] = colorValue; this.overlayImage[2] = " "; }, "Dropdown Text": () => this.dropdownButtonColor[1] = colorValue, }; @@ -903,7 +798,6 @@ findGradientType(menu) { const colorTypeMap = { Textbox: { newColorType: "textBoxColor", ind: 0 }, - "Input Box": { newColorType: "inputFieldColor", ind: 1 }, "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 } }; if (colorTypeMap[menu]) { @@ -915,72 +809,97 @@ } setGradient(args) { + if (args.COLOR_TYPE === "Input Box") throw new Error ("As of Better Input V4, this Option no Longer Works"); const newColorType = this.findGradientType(args.COLOR_TYPE); const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; - if (newColorType[0] !== "button") { - this[newColorType][0] = gradientColor; - } else { - const buttonInfo = this.buttonJSON[newColorType[1]]; - buttonInfo.color = gradientColor; - } + if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; + else this.buttonJSON[newColorType[1]].color = gradientColor; this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } - setCircleGradient(args) { const newColorType = this.findGradientType(args.COLOR_TYPE); const newPos = [args.X + 50, args.Y + 50]; const gradientColor = `radial-gradient(circle at ${newPos[0]}% ${newPos[1]}%, ${args.COLOR2}, ${args.COLOR1})`; - if (newColorType[0] !== "button") { - this[newColorType][0] = gradientColor; - } else { - const buttonInfo = this.buttonJSON[newColorType[1]]; - buttonInfo.color = gradientColor; - } + if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; + else this.buttonJSON[newColorType[1]].color = gradientColor; this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } - setBorderRadius(args) { - const element = args.ELEMENT; - let value = Math.max(args.VALUE, 0); - const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; - const elementIndex = elementMap[element]; - if (elementIndex !== undefined) { - this.overlayBorderRadius[elementIndex] = value; - } else if (this.buttonJSON[element]) { - this.buttonJSON[element].borderRadius = value; - } + callStyling(element, value, type, elements) { + const elementIndex = elements[element]; + if (elementIndex !== undefined) this.mainUIinfo[elementIndex] = value; + else if (this.buttonJSON[element]) this.buttonJSON[element][type] = value; this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } + setBorder(args) { + const width = Scratch.Cast.toNumber(args.WIDTH); + const string = `${width}px ${args.TYPE} ${args.COLOR}`; + this.callStyling( + args.ELEMENT, string, "border", + { Textbox: 3, "Input Box": 4, "Dropdown Button": 5 } + ); + } + + setBorderRadius(args) { + this.callStyling( + args.ELEMENT, Math.max(args.VALUE, 0), "borderRadius", + { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 } + ); + } + + setPadding(args) { + const casted = [ + Scratch.Cast.toNumber(args.N1), Scratch.Cast.toNumber(args.N2), + Scratch.Cast.toNumber(args.N3), Scratch.Cast.toNumber(args.N4) + ]; + let pad = `${casted[0]}px ${casted[1]}px ${casted[2]}px ${casted[3]}px`; + this.callStyling( + args.ELEMENT, pad, "padding", + { Textbox: 6, "Input Box": 7, "Dropdown Button": 8 } + ); + } + + setDropShadow(args) { + const casted = [ + Scratch.Cast.toNumber(args.x), Scratch.Cast.toNumber(args.y), + Scratch.Cast.toNumber(args.z), + ]; + let shadow = args.z === 0 ? "none" : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; + this.callStyling( + args.ELEMENT.slice(0, -5), shadow, "dropShadow", + { "Question": 9, "Input": 10, "Dropdown": 11 } + ); + } + + setOutline(args) { + const thick = Scratch.Cast.toNumber(args.THICK); + this.callStyling( + args.ELEMENT.slice(0, -5), [args.COLOR, thick], "outline", + { "Question": 12, "Input": 13, "Dropdown": 14 } + ); + } + setShadow(args) { - const shadowMap = { Size: 2, X: 0, Y: 1, Opacity: 3 }; + const shadowMap = { Size: 2, X: 0, Y: 1 }; const propertyIndex = shadowMap[args.SHADOW]; - if (propertyIndex !== undefined) { - this.shadowS[propertyIndex] = args.AMT; - if (args.SHADOW === "Opacity") this.shadowS[propertyIndex] /= 100; - } + if (propertyIndex !== undefined) this.shadowS[propertyIndex] = args.AMT; this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setImage(args) { const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; const elementIndex = elementMap[args.ELEMENT]; - if (elementIndex !== undefined) { - this.overlayImage[elementIndex] = args.IMAGE; - } else if (this.buttonJSON[args.ELEMENT]) { - this.buttonJSON[args.ELEMENT].image = args.IMAGE; - } + if (elementIndex !== undefined) this.overlayImage[elementIndex] = args.IMAGE; + else if (this.buttonJSON[args.ELEMENT]) this.buttonJSON[args.ELEMENT].image = args.IMAGE; this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } scaleImage(args) { const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; const elementIndex = elementMap[args.ELEMENT]; - if (elementIndex !== undefined) { - this.imgScale[elementIndex] = args.SCALE; - } else if (this.buttonJSON[args.ELEMENT]) { - this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; - } + if (elementIndex !== undefined) this.imgScale[elementIndex] = args.SCALE; + else if (this.buttonJSON[args.ELEMENT]) this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } @@ -1014,7 +933,6 @@ } getXpos() { return this.textBoxX * (screen.width / 400) } - getYpos() { return this.textBoxY * (screen.height / -300) } setFontSize(args) { this.fontSize = args.SIZE + "px" } @@ -1045,8 +963,7 @@ if (buttonMenu === "Dropdown") { this.DropdownText = text; } else if (this.buttonJSON[buttonMenu]) { - const buttonInfo = this.buttonJSON[buttonMenu]; - buttonInfo.name = text; + this.buttonJSON[buttonMenu].name = text; Scratch.vm.extensionManager.refreshBlocks(); } } @@ -1060,8 +977,12 @@ removeAskBoxes() { const overlaysToRemove = []; this.activeOverlays.forEach((overlay) => { - if (overlay && overlay.parentNode) { - overlay.parentNode.removeChild(overlay); + if (overlay) { + if (this.appendTarget[0] === "window" && overlay.parentNode) { + overlay.parentNode.removeChild(overlay); + } else if (overlay.parentNode.parentNode !== document.documentElement) { + overlay.parentNode.parentNode.removeChild(overlay.parentNode); + } overlaysToRemove.push(overlay); } if (this.askBoxPromises) { @@ -1073,6 +994,9 @@ this.activeOverlays = this.activeOverlays.filter((overlay) => !overlaysToRemove.includes(overlay)); this.activeUI = []; this.askBoxInfo[0] = 0; + // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info + const bugged = document.querySelectorAll(`[class^="SP-ask-box"]`); + bugged.forEach((box) => { box.parentNode.removeChild(box) }); } askAndWaitForInput(args) { @@ -1085,23 +1009,31 @@ if (this.askBoxInfo[0] < this.askBoxInfo[1]) { const question = args.question; this.isWaitingForInput = true; + this.lastPressBtn = ""; this.askBoxInfo[0]++; let selectedOptions = []; return new Promise((resolve) => { const askBoxPromise = { resolve }; this.askBoxPromises.push(askBoxPromise); const overlay = document.createElement("div"); - overlay.classList.add("ask-box"); + overlay.classList.add("SP-ask-box"); + overlay.style.pointerEvents = "auto"; overlay.style.position = "fixed"; overlay.style.zIndex = "9999"; - overlay.style.padding = "15px"; overlay.style.fontSize = this.fontSize; - overlay.style.left = `${50 + this.textBoxX}%`; - overlay.style.top = `${50 + this.textBoxY}%`; + overlay.style.left = this.appendTarget[0] === "window" ? `${50 + this.textBoxX}%` : "0%"; + overlay.style.top = this.appendTarget[0] === "window" ? `${50 + this.textBoxY}%` : "0%"; + + const focusBG = document.createElement("div"); + focusBG.style.cssText = "pointer-events: auto; position: fixed; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 9998;"; + focusBG.className = "SP-ask-boxBG"; + focusBG.id = this.appendTarget[0]; + focusBG.style.left = this.appendTarget[0] === "window" ? "0%" : "-50%"; + focusBG.style.top = this.appendTarget[0] === "window" ? "0%" : "-50%"; overlayImageContainer = document.createElement("div"); - overlayImageContainer.style.width = '100%'; - overlayImageContainer.style.height = '100%'; + overlayImageContainer.style.width = "100%"; + overlayImageContainer.style.height = "100%"; overlayImageContainer.style.position = "absolute"; overlayImageContainer.style.top = 0; overlayImageContainer.style.left = 0; @@ -1130,16 +1062,15 @@ const questionText = document.createElement("div"); questionText.classList.add("question"); questionText.style.fontSize = this.fontSize; - questionText.style.marginBottom = "10px"; + if (this.uiOrder[0] !== "question") questionText.style.marginTop = "10px"; + if (this.uiOrder[0] === "question") questionText.style.marginBottom = "10px"; questionText.textContent = question; const inputField = document.createElement("input"); inputField.style.display = this.isInputEnabled ? "block" : "none"; - inputField.style.width = "94%"; - inputField.style.padding = "5px"; inputField.style.fontSize = this.fontSize; inputField.style.margin = "0 auto"; - inputField.type = this.isInputEnabled === "Color" ? "color" : this.isInputEnabled === "Number" ? "number" : "text"; + inputField.type = this.isInputEnabled.toLowerCase(); inputField.addEventListener("input", () => { this.userInput = inputField.value }); const buttonContainer = document.createElement("div"); buttonContainer.classList.add("button-container"); @@ -1150,14 +1081,14 @@ buttonContainer.appendChild(lineBreak); } else { const button = document.createElement("button"); - button.style.marginTop = "10px"; + if (this.uiOrder[0] !== "buttons") button.style.marginTop = "10px"; + if (this.uiOrder[2] !== "buttons") button.style.marginBottom = "10px"; button.style.marginRight = "5px"; - button.style.padding = "5px 10px"; - button.style.border = "none"; button.style.cursor = "pointer"; button.textContent = buttonInfo.name; button.style.display = "inline-block"; button.addEventListener("click", () => { + this.lastPressBtn = buttonInfo.name; this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; this.closeOverlay(overlay); resolve(); @@ -1171,8 +1102,6 @@ const dropdownButton = document.createElement("button"); dropdownButton.className = "dropbtn"; dropdownButton.textContent = this.DropdownText; - dropdownButton.style.padding = "5px 10px"; - dropdownButton.style.border = "none"; const dropdownContent = document.createElement("div"); dropdownContent.id = "myDropdown"; dropdownContent.className = "dropdown-content"; @@ -1204,6 +1133,7 @@ }); document.body.appendChild(dropdown); dropdownButton.addEventListener("click", () => { + this.lastPressBtn = this.DropdownText; dropdownContent.style.display = this.isDropdownOpen ? "none" : "block"; this.isDropdownOpen = !this.isDropdownOpen; }); @@ -1217,13 +1147,9 @@ slider.max = this.sliderInfo[1]; slider.value = this.sliderInfo[2]; if (this.isInputEnabled.includes("Vertical")) { - for (let i = 0; i < 3; i++) { - sliderContainer.appendChild(document.createElement("br")); - } + for (let i = 0; i < 3; i++) { sliderContainer.appendChild(document.createElement("br")) } sliderContainer.appendChild(slider); - for (let i = 0; i < 4; i++) { - sliderContainer.appendChild(document.createElement("br")); - } + for (let i = 0; i < 4; i++) { sliderContainer.appendChild(document.createElement("br")) } } else { sliderContainer.appendChild(slider) } const valueDisplay = document.createElement("span"); valueDisplay.classList.add("slider-value"); @@ -1234,59 +1160,76 @@ valueDisplay.textContent = slider.value; this.userInput = valueDisplay.textContent; }); - - overlay.appendChild(questionText); - if (this.isInputEnabled !== "Disabled") { - if (this.isInputEnabled === "Enabled" || this.isInputEnabled === "Color" || this.isInputEnabled === "Number") { - overlay.appendChild(inputField); - } else if (this.isInputEnabled.includes("Dropdown")) { - overlay.appendChild(dropdownButton); - overlay.appendChild(dropdownContent); - overlay.appendChild(document.createElement("br")); - } else { - overlay.appendChild(sliderContainer); - overlay.appendChild(valueDisplay); - overlay.appendChild(document.createElement("br")); + for (const item of this.uiOrder) { + switch (item) { + case "question": { overlay.appendChild(questionText); break } + case "input": + if (this.isInputEnabled !== "Disabled") { + if (this.isInputEnabled === "Enabled" || this.isInputEnabled === "Color" || + this.isInputEnabled === "Number" || this.isInputEnabled === "Password" + ) { + overlay.appendChild(inputField); + } else if (this.isInputEnabled.includes("Dropdown")) { + overlay.appendChild(dropdownButton); + overlay.appendChild(dropdownContent); + overlay.appendChild(document.createElement("br")); + } else { + overlay.appendChild(sliderContainer); + overlay.appendChild(valueDisplay); + overlay.appendChild(document.createElement("br")); + } + } + break; + case "buttons": { overlay.appendChild(buttonContainer); break } } } - overlay.appendChild(buttonContainer); overlay.appendChild(overlayImageContainer); - document.body.appendChild(overlay); + if (this.appendTarget[0] === "window") { + document.body.appendChild(overlay); + if (this.appendTarget[1]) document.body.appendChild(focusBG); + } inputField.focus(); inputField.value = this.defaultValue; - const resizeHandler = () => { - overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; - overlay.style.top = `${this.textBoxY !== null ? 50 + this.textBoxY : 50}%`; - }; this.activeOverlays.push(overlay); this.activeUI.push({ overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField } }); - document.addEventListener("fullscreenchange", resizeHandler); - document.addEventListener("webkitfullscreenchange", resizeHandler); - document.addEventListener("mozfullscreenchange", resizeHandler); - document.addEventListener("MSFullscreenChange", resizeHandler); - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === "childList" && mutation.removedNodes.contains(overlay)) { - document.removeEventListener("fullscreenchange", resizeHandler); - document.removeEventListener("webkitfullscreenchange", resizeHandler); - document.removeEventListener("mozfullscreenchange", resizeHandler); - document.removeEventListener("MSFullscreenChange", resizeHandler); - observer.disconnect(); + if (this.appendTarget[0] === "window") { + const resizeHandler = () => { + overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; + overlay.style.top = `${this.textBoxY !== null ? 50 + this.textBoxY : 50}%`; + }; + document.addEventListener("fullscreenchange", resizeHandler); + document.addEventListener("webkitfullscreenchange", resizeHandler); + document.addEventListener("mozfullscreenchange", resizeHandler); + document.addEventListener("MSFullscreenChange", resizeHandler); + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if (mutation.type === "childList" && Array.from(mutation.removedNodes).includes(overlay)) { + document.removeEventListener("fullscreenchange", resizeHandler); + document.removeEventListener("webkitfullscreenchange", resizeHandler); + document.removeEventListener("mozfullscreenchange", resizeHandler); + document.removeEventListener("MSFullscreenChange", resizeHandler); + observer.disconnect(); + } } - } - }); - observer.observe(overlay.parentNode, { childList: true }); - document.body.appendChild(overlay); + }); + observer.observe(overlay.parentNode, { childList: true }); + document.body.appendChild(overlay); + } else { + if (this.appendTarget[1]) vm.renderer.addOverlay(focusBG, "scale-centered"); + vm.renderer.addOverlay(overlay, "scale-centered"); + } inputField.focus(); this.updateOverlay(overlay); }); } } - closeOverlay(overlay) { if (this.askBoxInfo[0] < 2) this.isWaitingForInput = false; this.isDropdownOpen = false; this.askBoxInfo[0]--; + let usedBG = document.querySelectorAll(".SP-ask-boxBG"); + usedBG = usedBG[usedBG.length - 1]; + // ^ Prioritizes Textboxes on Window const index = this.activeOverlays.indexOf(overlay); setTimeout(() => { if (index !== -1) { @@ -1294,17 +1237,23 @@ this.askBoxPromises.splice(index, 1); } delete this.activeUI[overlay]; - document.body.removeChild(overlay); + if (this.appendTarget[0] === "window") document.body.removeChild(overlay); + else vm.renderer.removeOverlay(overlay); + if (usedBG) { + if (usedBG.id === "window") document.body.removeChild(usedBG); + else vm.renderer.removeOverlay(usedBG); + } }, this.Timeout * 1000); } setButton(args) { if (args.BUTTON === "add") { this.buttonJSON[args.NAME] = { - borderRadius: 5, + borderRadius: 5, border: "1px none #000000", color: "#0074D9", textColor: "#ffffff", - name: args.NAME, - image: "", imgScale: 100 + name: args.NAME, padding: "5px 10px", + image: "", imgScale: 100, + dropShadow: "none", outline: ["", 0] }; } else { delete this.buttonJSON[args.NAME] } Scratch.vm.extensionManager.refreshBlocks(); @@ -1315,6 +1264,8 @@ Scratch.vm.extensionManager.refreshBlocks(); } + lastButton() { return this.lastPressBtn } + isWaitingInput() { return this.isWaitingForInput } isDropdown() { return this.isDropdownOpen } @@ -1341,9 +1292,26 @@ setDefaultV(args) { this.defaultValue = args.defaultV } - setEnable() { throw new Error("This block is removed in Better Input V3. Please use the more powerful and better blocks") } - getBoxCount() { throw new Error("This block is removed in Better Input V3. Please use the more powerful and better blocks") } - getMaxCount() { throw new Error("This block is removed in Better Input V3. Please use the more powerful and better blocks") } + setAppend(args) { this.appendTarget[0] = args.TARGET } + setFocus(args) { this.appendTarget[1] = args.TYPE === "Enabled" } + + setUI(args) { + let array; + try { array = JSON.parse(args.ARRAY.toLowerCase()) } catch { return } + if (!Array.isArray(array)) return; + const allowedUI = ["question", "input", "buttons"]; + let filteredArray = [...new Set(array.filter(element => allowedUI.includes(element)))]; + allowedUI.forEach(element => { + if (!filteredArray.includes(element)) filteredArray.push(element); + }); + this.uiOrder = filteredArray; + } + + getUIOrder() { return JSON.stringify(this.uiOrder) } + + setEnable() { throw new Error("This Block has been removed since Better Input V3. Please use the New Powerful Blocks") } + getBoxCount() { return this.askBoxInfo[0] } //Legacy + getMaxCount() { return this.askBoxInfo[1] } //Legacy } Scratch.extensions.register(new BetterInputSP()); From 194d1619e65fa8f5a4d6d53e2b3447badca7f3f4 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 28 Jan 2024 22:15:13 -0800 Subject: [PATCH 28/46] Update BetterInput.js --- extensions/SharkPool/BetterInput.js | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js index effa75ddd4..1d4083b89e 100644 --- a/extensions/SharkPool/BetterInput.js +++ b/extensions/SharkPool/BetterInput.js @@ -26,6 +26,7 @@ let newColorType = ""; let overlayImageContainer = ""; + const vm = Scratch.vm; const fontMenu = [ "Scratch", "Sans Serif", "Serif", "Handwriting", "Marker", "Curly", "Pixel" From 2b683b05315d9a017e46d515244b1190a806bd63 Mon Sep 17 00:00:00 2001 From: Muffin Date: Fri, 23 Feb 2024 22:46:51 -0600 Subject: [PATCH 29/46] add to homepage, npm run format --- extensions/SharkPool/Better-Input.js | 1763 ++++++++++++++++++++++++++ extensions/SharkPool/BetterInput.js | 1319 ------------------- extensions/extensions.json | 1 + 3 files changed, 1764 insertions(+), 1319 deletions(-) create mode 100644 extensions/SharkPool/Better-Input.js delete mode 100644 extensions/SharkPool/BetterInput.js diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js new file mode 100644 index 0000000000..f012c21251 --- /dev/null +++ b/extensions/SharkPool/Better-Input.js @@ -0,0 +1,1763 @@ +// Name: Better Input +// ID: BetterInputSP +// Description: Expansion of the "ask and wait" Blocks +// By: SharkPool + +// Version V.4.0.0 + +(function (Scratch) { + "use strict"; + if (!Scratch.extensions.unsandboxed) + throw new Error("Better Input must run unsandboxed"); + + const menuIconURI = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; + + const blockIconURI = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + + const formatIcon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + + const colorIcon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; + + const effectIcon = + "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + + let newColorType = ""; + let overlayImageContainer = ""; + const vm = Scratch.vm; + const fontMenu = [ + "Scratch", + "Sans Serif", + "Serif", + "Handwriting", + "Marker", + "Curly", + "Pixel", + ]; + + class BetterInputSP { + constructor() { + this.activeOverlays = []; + this.activeUI = []; + this.askBoxPromises = []; + this.isWaitingForInput = false; + this.isDropdownOpen = false; + this.userInput = " "; + this.defaultValue = ""; + this.textBoxX = 0; + this.textBoxY = 0; + this.askBoxInfo = [0, 1]; + this.appendTarget = ["window", false]; + this.forceInput = "Disabled"; + this.overlayInput = null; + this.uiOrder = ["question", "input", "buttons"]; + + this.optionList = ["Option 1", "Option 2", "Option 3"]; + this.sliderInfo = [0, 100, 50]; + this.Timeout = 0; + + this.shadowEnabled = true; + this.isInputEnabled = "Enabled"; + this.DropdownText = "Dropdown"; + this.fontSize = "14px"; + this.textAlign = "left"; + this.fontFamily = "Sans Serif"; + // overlay + Image, input, dropdown button + this.mainUIinfo = [ + 5, + 4, + 5, + "1px none #000000", + "1px solid #000000", + "1px none #000000", + "15px", + "5px", + "5px 10px", + "none", + "none", + "none", + ["", 0], + ["", 0], + ["", 0], + ]; + this.lastPressBtn = ""; + this.buttonJSON = { + Submit: { + color: "#0074D9", + textColor: "#ffffff", + name: "Submit", + image: "", + imgScale: 100, + borderRadius: 5, + border: "1px none #000000", + padding: "5px 10px", + dropShadow: "none", + outline: ["", 0], + }, + Cancel: { + color: "#d9534f", + textColor: "#ffffff", + name: "Cancel", + image: "", + imgScale: 100, + borderRadius: 5, + border: "1px none #000000", + padding: "5px 10px", + dropShadow: "none", + outline: ["", 0], + }, + }; + + this.questionColor = "#000000"; + this.inputColor = "#000000"; + this.textBoxColor = ["#ffffff"]; + this.inputFieldColor = "#ffffff"; + this.dropdownButtonColor = ["#5f5f5f", "#ffffff"]; + this.overlayImage = [" ", " ", " "]; + + this.Blur = 0; + this.Brightness = 0; + this.Opacity = 100; + this.Invert = 0; + this.Saturation = 100; + this.Hue = 0; + this.Sepia = 0; + this.Contrast = 100; + this.Scale = 100; + this.SkewX = 0; + this.SkewY = 0; + this.Rotation = 90; + this.imgScale = [100, 100, 100]; + this.shadowS = [0, 0, 5, "#000000"]; + } + + getInfo() { + return { + id: "BetterInputSP", + name: "Better Input", + color1: "#9400ff", + color2: "#7800cd", + color3: "#6900b3", + menuIconURI, + blockIconURI, + blocks: [ + { + opcode: "askAndWait", + blockType: Scratch.BlockType.COMMAND, + text: "ask [question] and wait", + arguments: { + question: { + type: Scratch.ArgumentType.STRING, + defaultValue: "What is your name?", + }, + }, + }, + { + opcode: "askAndWaitForInput", + blockType: Scratch.BlockType.REPORTER, + text: "ask [question] and wait", + arguments: { + question: { + type: Scratch.ArgumentType.STRING, + defaultValue: "What is your name?", + }, + }, + }, + { + opcode: "getUserInput", + blockType: Scratch.BlockType.REPORTER, + text: "user input", + }, + { + opcode: "setDefaultV", + blockType: Scratch.BlockType.COMMAND, + text: "set default value to [defaultV]", + arguments: { + defaultV: { + type: Scratch.ArgumentType.STRING, + defaultValue: "My Name Is...", + }, + }, + }, + { + opcode: "removeAskBoxes", + blockType: Scratch.BlockType.COMMAND, + text: "remove all ask boxes", + }, + { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, + { + opcode: "setEnable", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: true, + text: "set [ENABLE_MENU] to be [ACTION]", + arguments: { + ENABLE_MENU: { + type: Scratch.ArgumentType.STRING, + menu: "enableMenu", + }, + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "inputActionMenu", + }, + }, + }, + { + opcode: "getBoxCount", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, + text: "box count", + }, + { + opcode: "getMaxCount", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, + text: "box limit", + }, + { + opcode: "setFontSize", + blockType: Scratch.BlockType.COMMAND, + text: "set font size to [SIZE]", + blockIconURI: formatIcon, + arguments: { + SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 14 }, + }, + }, + { + opcode: "setTextAlignment", + blockType: Scratch.BlockType.COMMAND, + text: "set alignment to [ALIGNMENT]", + blockIconURI: formatIcon, + arguments: { + ALIGNMENT: { + type: Scratch.ArgumentType.STRING, + menu: "alignmentMenu", + }, + }, + }, + { + opcode: "setFontFamily", + blockType: Scratch.BlockType.COMMAND, + text: "set font to [FONT]", + blockIconURI: formatIcon, + arguments: { + FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu" }, + }, + }, + { + opcode: "setDropShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] shadow to x [x] y [y] z [z] color [COLOR]", + arguments: { + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, + x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 2 }, + COLOR: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#ff0000", + }, + }, + }, + { + opcode: "setOutline", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] outline to [COLOR] thickness [THICK]", + arguments: { + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, + COLOR: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#ff0000", + }, + THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + "---", + { + opcode: "setInputType", + blockType: Scratch.BlockType.COMMAND, + text: "set Input Box to be [ACTION]", + blockIconURI: formatIcon, + arguments: { + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "inputActionMenu", + }, + }, + }, + { + opcode: "setDropdown", + blockType: Scratch.BlockType.COMMAND, + text: "set dropdown options to array: [DROPDOWN]", + blockIconURI: formatIcon, + arguments: { + DROPDOWN: { + type: Scratch.ArgumentType.STRING, + defaultValue: '["Option 1", "Option 2", "Option 3"]', + }, + }, + }, + { + opcode: "setSlider", + blockType: Scratch.BlockType.COMMAND, + text: "set slider to min: [MIN] max: [MAX] default: [DEFAULT]", + blockIconURI: formatIcon, + arguments: { + MIN: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, + DEFAULT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 }, + }, + }, + { blockType: Scratch.BlockType.LABEL, text: "Buttons" }, + { + opcode: "setButton", + blockType: Scratch.BlockType.COMMAND, + text: "[BUTTON] button named [NAME]", + blockIconURI: formatIcon, + arguments: { + BUTTON: { type: Scratch.ArgumentType.STRING, menu: "buttonType" }, + NAME: { + type: Scratch.ArgumentType.STRING, + defaultValue: "Submit", + }, + }, + }, + { + opcode: "deleteAllButtons", + blockType: Scratch.BlockType.COMMAND, + text: "remove all buttons", + blockIconURI: formatIcon, + }, + { + opcode: "setButtonText", + blockType: Scratch.BlockType.COMMAND, + text: "set [BUTTON_MENU] button name to [TEXT]", + blockIconURI: formatIcon, + arguments: { + BUTTON_MENU: { + type: Scratch.ArgumentType.STRING, + menu: "buttonMenu", + }, + TEXT: { + type: Scratch.ArgumentType.STRING, + defaultValue: "my dropdown", + }, + }, + }, + { + opcode: "lastButton", + blockType: Scratch.BlockType.REPORTER, + text: "last pressed button", + blockIconURI: formatIcon, + }, + { blockType: Scratch.BlockType.LABEL, text: "Positioning" }, + { + opcode: "setPrePosition", + blockType: Scratch.BlockType.COMMAND, + text: "preset textbox position to x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + }, + }, + { + opcode: "setPosition", + blockType: Scratch.BlockType.COMMAND, + text: "set textbox position to x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + }, + }, + { + opcode: "changePosition", + blockType: Scratch.BlockType.COMMAND, + text: "change textbox position by x: [X] y: [Y]", + blockIconURI: formatIcon, + arguments: { + X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + }, + }, + { + opcode: "getXpos", + blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, + text: "x position", + }, + { + opcode: "getYpos", + blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, + text: "y position", + }, + { + opcode: "setDirection", + blockType: Scratch.BlockType.COMMAND, + text: "set direction to [ROTATE]", + blockIconURI: formatIcon, + arguments: { + ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 90 }, + }, + }, + { + opcode: "changeDirection", + blockType: Scratch.BlockType.COMMAND, + text: "change direction by [ROTATE]", + blockIconURI: formatIcon, + arguments: { + ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 15 }, + }, + }, + { + opcode: "reportDirection", + blockType: Scratch.BlockType.REPORTER, + text: "direction", + blockIconURI: formatIcon, + }, + { blockType: Scratch.BlockType.LABEL, text: "Visual Settings" }, + { + opcode: "setColorSettings", + blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to [COLOR]", + blockIconURI: colorIcon, + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "colorSettingsMenu", + }, + COLOR: { + type: Scratch.ArgumentType.COLOR, + defaultValue: "#000000", + }, + }, + }, + { + opcode: "setGradient", + blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to gradient with [COLOR1] and [COLOR2] with direction [DIR]", + hideFromPalette: true, //deprecated but needed for support + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + COLOR1: { type: Scratch.ArgumentType.COLOR }, + COLOR2: { type: Scratch.ArgumentType.COLOR }, + DIR: { type: Scratch.ArgumentType.ANGLE }, + }, + }, + { + opcode: "setCircleGradient", + blockType: Scratch.BlockType.COMMAND, + text: "set [COLOR_TYPE] color to radial gradient with [COLOR1] and [COLOR2] at x [X] y [Y]", + hideFromPalette: true, //deprecated but needed for support + arguments: { + COLOR_TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + COLOR1: { type: Scratch.ArgumentType.COLOR }, + COLOR2: { type: Scratch.ArgumentType.COLOR }, + X: { type: Scratch.ArgumentType.NUMBER }, + Y: { type: Scratch.ArgumentType.NUMBER }, + }, + }, + "---", + { + opcode: "setImage", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] image to [IMAGE]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + IMAGE: { + type: Scratch.ArgumentType.STRING, + defaultValue: "input-url-here", + }, + }, + }, + { + opcode: "scaleImage", + blockType: Scratch.BlockType.COMMAND, + text: "scale [ELEMENT] image to [SCALE]%", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + SCALE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, + }, + }, + "---", + { + opcode: "enableShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set box shadow to be [ACTION]", + blockIconURI: colorIcon, + arguments: { + ACTION: { + type: Scratch.ArgumentType.STRING, + menu: "buttonActionMenu", + }, + }, + }, + { + opcode: "setShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set box shadow [SHADOW] to [AMT]", + blockIconURI: colorIcon, + arguments: { + SHADOW: { + type: Scratch.ArgumentType.STRING, + menu: "shadowStuff", + }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + "---", + { + opcode: "setBorder", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] border to [TYPE] color [COLOR] width [WIDTH]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + TYPE: { type: Scratch.ArgumentType.STRING, menu: "borderTypes" }, + COLOR: { type: Scratch.ArgumentType.COLOR }, + WIDTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + { + opcode: "setBorderRadius", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] border radius to [VALUE]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + VALUE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + { + opcode: "setPadding", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] padding to T: [N1] B: [N3] L: [N4] R: [N2]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { + type: Scratch.ArgumentType.STRING, + menu: "elementMenu", + }, + N1: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N2: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N3: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N4: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + { blockType: Scratch.BlockType.LABEL, text: "Effects" }, + { + opcode: "resetEffect", + blockType: Scratch.BlockType.COMMAND, + text: "reset effects", + blockIconURI: effectIcon, + }, + { + opcode: "setEffect", + blockType: Scratch.BlockType.COMMAND, + text: "set effect [EFFECT] to [AMT]", + blockIconURI: effectIcon, + arguments: { + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + { + opcode: "changeEffect", + blockType: Scratch.BlockType.COMMAND, + text: "change effect [EFFECT] by [AMT]", + blockIconURI: effectIcon, + arguments: { + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + { + opcode: "showEffect", + blockType: Scratch.BlockType.REPORTER, + text: "effect [EFFECT]", + blockIconURI: effectIcon, + arguments: { + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, + }, + }, + "---", + { + opcode: "setTimeout", + blockType: Scratch.BlockType.COMMAND, + text: "when submitted delete textbox after [TIME] secs", + blockIconURI: effectIcon, + arguments: { + TIME: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + }, + }, + { + opcode: "reportTimeout", + blockType: Scratch.BlockType.REPORTER, + text: "current textbox timeout", + blockIconURI: effectIcon, + }, + { blockType: Scratch.BlockType.LABEL, text: "Operations" }, + { + opcode: "setUI", + blockType: Scratch.BlockType.COMMAND, + text: "set UI order to [ARRAY]", + arguments: { + ARRAY: { + type: Scratch.ArgumentType.STRING, + defaultValue: '["question", "input", "buttons"]', + }, + }, + }, + { + opcode: "getUIOrder", + blockType: Scratch.BlockType.REPORTER, + text: "UI order", + }, + "---", + { + opcode: "setAppend", + blockType: Scratch.BlockType.COMMAND, + text: "append next textbox to [TARGET]", + arguments: { + TARGET: { type: Scratch.ArgumentType.STRING, menu: "appendMenu" }, + }, + }, + { + opcode: "setFocus", + blockType: Scratch.BlockType.COMMAND, + text: "toggle focus mode to [TYPE]", + arguments: { + TYPE: { + type: Scratch.ArgumentType.STRING, + menu: "buttonActionMenu", + }, + }, + }, + "---", + { + opcode: "isWaitingInput", + blockType: Scratch.BlockType.BOOLEAN, + text: "is waiting?", + }, + { + opcode: "isDropdown", + blockType: Scratch.BlockType.BOOLEAN, + text: "is dropdown open?", + }, + { + opcode: "setSubmitEvent", + blockType: Scratch.BlockType.COMMAND, + text: "set force input to [ENTER]", + arguments: { + ENTER: { type: Scratch.ArgumentType.STRING, menu: "enterMenu" }, + }, + }, + { + opcode: "setMaxBoxCount", + blockType: Scratch.BlockType.COMMAND, + text: "set max box count to: [MAX]", + arguments: { + MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }, + }, + }, + { + opcode: "getBoxInfo", + blockType: Scratch.BlockType.REPORTER, + text: "textbox [INFO]", + arguments: { + INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo" }, + }, + }, + ], + menus: { + enableMenu: { + acceptReporters: true, + items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"], + }, + // ^ Old Menu ^ (Needed for V2 Support) + fontMenu: { acceptReporters: true, items: "allFonts" }, + buttonMenu: { + acceptReporters: true, + items: this.allButtons(["Dropdown"], false), + }, + elementMenu: { + acceptReporters: true, + items: this.allButtons( + ["Textbox", "Input Box", "Dropdown Button"], + false + ), + }, + colorSettingsMenu: { + acceptReporters: true, + items: this.allButtons( + [ + "Textbox", + "Question Text", + "Textbox Shadow", + "Input Text", + "Input Box", + "Dropdown Button", + "Dropdown Text", + ], + true + ), + }, + textsMenu: { + acceptReporters: true, + items: this.allButtons( + ["Question Text", "Input Text", "Dropdown Text"], + true, + true + ), + }, + appendMenu: ["window", "canvas"], + buttonType: { acceptReporters: true, items: ["add", "remove"] }, + buttonActionMenu: { + acceptReporters: true, + items: ["Enabled", "Disabled"], + }, + alignmentMenu: { + acceptReporters: true, + items: ["left", "right", "center"], + }, + shadowStuff: { acceptReporters: true, items: ["Size", "X", "Y"] }, + boxInfo: { + acceptReporters: true, + items: ["count", "limit", "button count", "button names"], + }, + inputActionMenu: { + acceptReporters: true, + items: [ + "None", + "Text", + "Password", + "Number", + "Color", + "Dropdown", + "Multi-Select Dropdown", + "Horizontal Slider", + "Vertical Slider", + ], + }, + effectMenu: { + acceptReporters: true, + items: [ + "Blur", + "Brightness", + "Opacity", + "Invert", + "Saturation", + "Hue", + "Sepia", + "Contrast", + "Scale", + "SkewX", + "SkewY", + ], + }, + enterMenu: { + acceptReporters: true, + items: ["Disabled", "Enter Key", "Shift + Enter Key"], + }, + borderTypes: { + acceptReporters: true, + items: [ + "none", + "solid", + "dotted", + "dashed", + "double", + "groove", + "ridge", + "inset", + "outset", + ], + }, + }, + }; + } + + allFonts() { + const customFonts = Scratch.vm.runtime.fontManager + ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({ + text: i.name, + value: i.family, + })) + : []; + return [...fontMenu, ...customFonts]; + } + + allButtons(array, enableTxt, justTxt) { + let customBtn = Object.keys(this.buttonJSON); + if (justTxt) customBtn = customBtn.map((btn) => btn + " Text"); + else if (enableTxt) + customBtn.forEach((btn) => { + customBtn.push(btn + " Text"); + }); + return [...array, ...customBtn]; + } + + updateOverlayPos(overlay) { + if (this.Rotation > 359) this.Rotation = 0; + else if (this.Rotation < 1) this.Rotation = 360; + if (this.textBoxX !== null && this.textBoxY !== null) { + if (this.appendTarget[0] === "window") { + overlay.style.left = `${50 + this.textBoxX}%`; + overlay.style.top = `${50 + this.textBoxY}%`; + } + overlay.style.transform = ` + translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)`} + SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) + `; + } else { + overlay.style.left = "50%"; + overlay.style.top = "50%"; + } + } + updateOverlay(overlay) { + const newOpacity = this.Opacity / 100; + const newBrightness = this.Brightness + 100; + overlay.style.backgroundImage = ""; + overlay.style[ + this.textBoxColor[0].includes("gradient") + ? "backgroundImage" + : "backgroundColor" + ] = this.textBoxColor[0]; + overlay.style.boxShadow = this.shadowEnabled + ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px ${this.shadowS[3]}` + : "none"; + overlay.style.transform = ` + translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)`} + SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) + rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) + `; + overlay.style.filter = ` + blur(${this.Blur}px) brightness(${newBrightness}%) + invert(${this.Invert}%) saturate(${this.Saturation}%) + hue-rotate(${this.Hue}deg) sepia(${this.Sepia}%) + contrast(${this.Contrast}%) + `; + overlay.style.opacity = newOpacity; + overlay.style.border = this.mainUIinfo[3]; + overlay.style.padding = this.mainUIinfo[6]; + overlay.style.fontFamily = this.fontFamily; + overlay.style.textAlign = this.textAlign; + overlay.style.borderRadius = `${this.mainUIinfo[0]}px`; + overlayImageContainer.style.borderRadius = `${this.mainUIinfo[0]}px`; + overlayImageContainer.style.background = ""; + this.setImageStyles( + overlayImageContainer, + this.overlayImage[0], + this.imgScale[0] + ); + this.updateButtonImages(overlay); + } + updateButtonImages(overlay) { + let text = overlay.querySelector(".question"); + if (text) { + text.style.color = this.questionColor; + text.style.textShadow = this.mainUIinfo[9]; + this.tryOutline(text, this.mainUIinfo[12][0], this.mainUIinfo[12][1]); + } + const inputField = overlay.querySelector("input"); + if (inputField) { + inputField.style.width = + this.isInputEnabled === "Color" ? "100%" : "auto"; + inputField.style.background = ""; + inputField.style.fontFamily = this.fontFamily; + inputField.style[ + this.inputFieldColor.includes("gradient") + ? "backgroundImage" + : "backgroundColor" + ] = this.inputFieldColor; + inputField.style.color = this.inputColor; + inputField.style.textShadow = this.mainUIinfo[10]; + this.tryOutline( + inputField, + this.mainUIinfo[13][0], + this.mainUIinfo[13][1] + ); + inputField.style.border = this.mainUIinfo[4]; + inputField.style.borderRadius = `${this.mainUIinfo[1]}px`; + inputField.style.padding = this.mainUIinfo[7]; + this.setImageStyles(inputField, this.overlayImage[1], this.imgScale[1]); + } + + const dropBtn = overlay.querySelector("button.dropbtn"); + if (dropBtn) { + dropBtn.style.backgroundImage = ""; + dropBtn.style.fontFamily = this.fontFamily; + dropBtn.style.color = this.dropdownButtonColor[1]; + dropBtn.style.borderRadius = `${this.mainUIinfo[2]}px`; + dropBtn.style.border = this.mainUIinfo[5]; + dropBtn.style.padding = this.mainUIinfo[8]; + dropBtn.style.textShadow = this.mainUIinfo[11]; + this.tryOutline( + dropBtn, + this.mainUIinfo[14][0], + this.mainUIinfo[14][1] + ); + dropBtn.style[ + this.dropdownButtonColor[0].includes("gradient") + ? "backgroundImage" + : "backgroundColor" + ] = this.dropdownButtonColor[0]; + this.setImageStyles(dropBtn, this.overlayImage[2], this.imgScale[2]); + } + const buttonContainer = overlay.querySelector(".button-container"); + if (buttonContainer) { + const buttons = buttonContainer.querySelectorAll("button"); + buttons.forEach((button, index) => { + const buttonName = Object.keys(this.buttonJSON)[index]; + const buttonInfo = this.buttonJSON[buttonName]; + if (buttonInfo) { + button.style.color = buttonInfo.textColor; + button.style.fontFamily = this.fontFamily; + button.style.borderRadius = `${buttonInfo.borderRadius}px`; + button.style.border = buttonInfo.border; + button.style.padding = buttonInfo.padding; + button.style.textShadow = buttonInfo.dropShadow; + this.tryOutline( + button, + buttonInfo.outline[0], + buttonInfo.outline[1] + ); + button.style.background = ""; + button.style[ + buttonInfo.color.includes("gradient") + ? "backgroundImage" + : "background" + ] = buttonInfo.color; + this.setImageStyles(button, buttonInfo.image, buttonInfo.imgScale); + } + }); + } + } + tryOutline(element, color, thick) { + element.style.webkitTextStrokeColor = color; + element.style.webkitTextStrokeWidth = `${thick}px`; + //multi-platform support cuz we cant have nice things + element.style.textStrokeColor = color; + element.style.textStrokeWidth = `${thick}px`; + element.style.mozTextStrokeColor = color; + element.style.mozTextStrokeWidth = `${thick}px`; + } + + setImageStyles(element, url, scale) { + if (Scratch.Cast.toString(url).length > 5) { + Scratch.canFetch(encodeURI(url)).then((canFetch) => { + if (canFetch) { + element.style.background = `url(${encodeURI(url)})`; + element.style.backgroundSize = `${scale}%`; + } else { + console.log("Cannot fetch content from the URL"); + } + }); + } + } + + showEffect(args) { + return this[args.EFFECT]; + } + + setEffect(args) { + this[args.EFFECT] = args.AMT; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + changeEffect(args) { + const effect = args.EFFECT; + this[effect] = this[effect] + args.AMT; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + resetEffect() { + this.Blur = 0; + this.Brightness = 0; + this.Opacity = 100; + this.Invert = 0; + this.Saturation = 100; + this.Hue = 0; + this.Sepia = 0; + this.Contrast = 100; + this.Scale = 100; + this.SkewX = 0; + this.SkewY = 0; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + setColorSettings(args) { + const colorType = args.COLOR_TYPE; + const colorValue = args.COLOR; + const colorTypeMap = { + "Question Text": () => (this.questionColor = colorValue), + "Input Text": () => (this.inputColor = colorValue), + Textbox: () => { + this.textBoxColor[0] = colorValue; + this.overlayImage[0] = " "; + }, + "Textbox Shadow": () => { + this.shadowS[3] = colorValue; + }, + "Input Box": () => { + this.inputFieldColor = colorValue; + this.overlayImage[1] = " "; + }, + "Dropdown Button": () => { + this.dropdownButtonColor[0] = colorValue; + this.overlayImage[2] = " "; + }, + "Dropdown Text": () => (this.dropdownButtonColor[1] = colorValue), + }; + const buttonInfo = + this.buttonJSON[colorType] || + this.buttonJSON[colorType.replace(" Text", "")]; + if (buttonInfo) { + if (colorType.includes(" Text")) { + buttonInfo.textColor = colorValue; + } else { + buttonInfo.color = colorValue; + buttonInfo.image = " "; + } + } + const applyColor = colorTypeMap[colorType]; + if (applyColor) applyColor(); + this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + } + + findGradientType(menu) { + const colorTypeMap = { + Textbox: { newColorType: "textBoxColor", ind: 0 }, + "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 }, + }; + if (colorTypeMap[menu]) { + const { newColorType, ind } = colorTypeMap[menu]; + this.overlayImage[ind] = " "; + return newColorType; + } else if (this.buttonJSON[menu]) { + return ["button", menu]; + } + return menu; + } + + setGradient(args) { + if (args.COLOR_TYPE === "Input Box") + throw new Error("As of Better Input V4, this Option no Longer Works"); + const newColorType = this.findGradientType(args.COLOR_TYPE); + const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; + if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; + else this.buttonJSON[newColorType[1]].color = gradientColor; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + setCircleGradient(args) { + const newColorType = this.findGradientType(args.COLOR_TYPE); + const newPos = [args.X + 50, args.Y + 50]; + const gradientColor = `radial-gradient(circle at ${newPos[0]}% ${newPos[1]}%, ${args.COLOR2}, ${args.COLOR1})`; + if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; + else this.buttonJSON[newColorType[1]].color = gradientColor; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + callStyling(element, value, type, elements) { + const elementIndex = elements[element]; + if (elementIndex !== undefined) this.mainUIinfo[elementIndex] = value; + else if (this.buttonJSON[element]) this.buttonJSON[element][type] = value; + this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + } + + setBorder(args) { + const width = Scratch.Cast.toNumber(args.WIDTH); + const string = `${width}px ${args.TYPE} ${args.COLOR}`; + this.callStyling(args.ELEMENT, string, "border", { + Textbox: 3, + "Input Box": 4, + "Dropdown Button": 5, + }); + } + + setBorderRadius(args) { + this.callStyling(args.ELEMENT, Math.max(args.VALUE, 0), "borderRadius", { + Textbox: 0, + "Input Box": 1, + "Dropdown Button": 2, + }); + } + + setPadding(args) { + const casted = [ + Scratch.Cast.toNumber(args.N1), + Scratch.Cast.toNumber(args.N2), + Scratch.Cast.toNumber(args.N3), + Scratch.Cast.toNumber(args.N4), + ]; + let pad = `${casted[0]}px ${casted[1]}px ${casted[2]}px ${casted[3]}px`; + this.callStyling(args.ELEMENT, pad, "padding", { + Textbox: 6, + "Input Box": 7, + "Dropdown Button": 8, + }); + } + + setDropShadow(args) { + const casted = [ + Scratch.Cast.toNumber(args.x), + Scratch.Cast.toNumber(args.y), + Scratch.Cast.toNumber(args.z), + ]; + let shadow = + args.z === 0 + ? "none" + : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; + this.callStyling(args.ELEMENT.slice(0, -5), shadow, "dropShadow", { + Question: 9, + Input: 10, + Dropdown: 11, + }); + } + + setOutline(args) { + const thick = Scratch.Cast.toNumber(args.THICK); + this.callStyling( + args.ELEMENT.slice(0, -5), + [args.COLOR, thick], + "outline", + { Question: 12, Input: 13, Dropdown: 14 } + ); + } + + setShadow(args) { + const shadowMap = { Size: 2, X: 0, Y: 1 }; + const propertyIndex = shadowMap[args.SHADOW]; + if (propertyIndex !== undefined) this.shadowS[propertyIndex] = args.AMT; + this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + } + + setImage(args) { + const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; + const elementIndex = elementMap[args.ELEMENT]; + if (elementIndex !== undefined) + this.overlayImage[elementIndex] = args.IMAGE; + else if (this.buttonJSON[args.ELEMENT]) + this.buttonJSON[args.ELEMENT].image = args.IMAGE; + this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + } + + scaleImage(args) { + const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; + const elementIndex = elementMap[args.ELEMENT]; + if (elementIndex !== undefined) this.imgScale[elementIndex] = args.SCALE; + else if (this.buttonJSON[args.ELEMENT]) + this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; + this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + } + + setDirection(args) { + this.Rotation = Scratch.Cast.toNumber(args.ROTATE); + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + changeDirection(args) { + this.Rotation = this.Rotation + Scratch.Cast.toNumber(args.ROTATE); + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + reportDirection() { + return this.Rotation; + } + + setPrePosition(args) { + this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); + } + + setPosition(args) { + this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); + this.activeOverlays.forEach((overlay) => { + this.updateOverlayPos(overlay); + }); + } + + changePosition(args) { + this.textBoxX = + this.textBoxX + Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = + this.textBoxY + Scratch.Cast.toNumber(args.Y) / (screen.height / -300); + this.activeOverlays.forEach((overlay) => { + this.updateOverlayPos(overlay); + }); + } + + getXpos() { + return this.textBoxX * (screen.width / 400); + } + getYpos() { + return this.textBoxY * (screen.height / -300); + } + + setFontSize(args) { + this.fontSize = args.SIZE + "px"; + } + + setTextAlignment(args) { + this.textAlign = args.ALIGNMENT; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + setFontFamily(args) { + this.fontFamily = args.FONT; + this.activeOverlays.forEach((overlay) => { + this.updateOverlay(overlay); + }); + } + + setSlider(args) { + this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT]; + } + + setInputType(args) { + if (args.ACTION === "Text" || args.ACTION === "None") { + this.isInputEnabled = args.ACTION === "Text" ? "Enabled" : "Disabled"; + } else { + this.isInputEnabled = args.ACTION; + } + } + + enableShadow(args) { + this.shadowEnabled = args.ACTION === "Enabled"; + } + + setButtonText(args) { + const buttonMenu = args.BUTTON_MENU; + const text = args.TEXT; + if (buttonMenu === "Dropdown") { + this.DropdownText = text; + } else if (this.buttonJSON[buttonMenu]) { + this.buttonJSON[buttonMenu].name = text; + Scratch.vm.extensionManager.refreshBlocks(); + } + } + + setDropdown(args) { + try { + this.optionList = JSON.parse(args.DROPDOWN); + } catch { + this.optionList = ["Undefined Array Error"]; + } + } + + removeAskBoxes() { + const overlaysToRemove = []; + this.activeOverlays.forEach((overlay) => { + if (overlay) { + if (this.appendTarget[0] === "window" && overlay.parentNode) { + overlay.parentNode.removeChild(overlay); + } else if ( + overlay.parentNode.parentNode !== document.documentElement + ) { + overlay.parentNode.parentNode.removeChild(overlay.parentNode); + } + overlaysToRemove.push(overlay); + } + if (this.askBoxPromises) { + const index = this.activeOverlays.indexOf(overlay); + if (index !== -1) this.askBoxPromises[index].resolve("removed"); + } + }); + this.askBoxPromises = []; + this.activeOverlays = this.activeOverlays.filter( + (overlay) => !overlaysToRemove.includes(overlay) + ); + this.activeUI = []; + this.askBoxInfo[0] = 0; + // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info + const bugged = document.querySelectorAll(`[class^="SP-ask-box"]`); + bugged.forEach((box) => { + box.parentNode.removeChild(box); + }); + } + + askAndWaitForInput(args) { + if (this.askBoxInfo[0] < this.askBoxInfo[1]) { + return this.askAndWait(args).then(() => { + return this.getUserInput(); + }); + } + } + + askAndWait(args) { + if (this.askBoxInfo[0] < this.askBoxInfo[1]) { + const question = args.question; + this.isWaitingForInput = true; + this.lastPressBtn = ""; + this.askBoxInfo[0]++; + let selectedOptions = []; + return new Promise((resolve) => { + const askBoxPromise = { resolve }; + this.askBoxPromises.push(askBoxPromise); + const overlay = document.createElement("div"); + overlay.classList.add("SP-ask-box"); + overlay.style.pointerEvents = "auto"; + overlay.style.position = "fixed"; + overlay.style.zIndex = "9999"; + overlay.style.fontSize = this.fontSize; + overlay.style.left = + this.appendTarget[0] === "window" ? `${50 + this.textBoxX}%` : "0%"; + overlay.style.top = + this.appendTarget[0] === "window" ? `${50 + this.textBoxY}%` : "0%"; + + const focusBG = document.createElement("div"); + focusBG.style.cssText = + "pointer-events: auto; position: fixed; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 9998;"; + focusBG.className = "SP-ask-boxBG"; + focusBG.id = this.appendTarget[0]; + focusBG.style.left = + this.appendTarget[0] === "window" ? "0%" : "-50%"; + focusBG.style.top = this.appendTarget[0] === "window" ? "0%" : "-50%"; + + overlayImageContainer = document.createElement("div"); + overlayImageContainer.style.width = "100%"; + overlayImageContainer.style.height = "100%"; + overlayImageContainer.style.position = "absolute"; + overlayImageContainer.style.top = 0; + overlayImageContainer.style.left = 0; + overlayImageContainer.style.zIndex = "-1"; + if (this.forceInput !== "Disabled") { + const overlayInput = + this.forceInput === "Enter Key" + ? "Enter" + : this.forceInput === "Shift + Enter Key" + ? "ShiftEnter" + : this.forceInput; + const handleKeydown = (event) => { + if ( + (overlayInput === "ShiftEnter" && + event.shiftKey && + event.key === "Enter") || + event.key === overlayInput + ) { + this.userInput = inputField.value; + this.closeOverlay(overlay); + resolve(); + } + }; + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if ( + mutation.type === "childList" && + !document.contains(overlay) + ) { + document.removeEventListener("keydown", handleKeydown); + observer.disconnect(); + } + } + }); + observer.observe(document.body, { childList: true }); + document.addEventListener("keydown", handleKeydown); + } + + const questionText = document.createElement("div"); + questionText.classList.add("question"); + questionText.style.fontSize = this.fontSize; + if (this.uiOrder[0] !== "question") + questionText.style.marginTop = "10px"; + if (this.uiOrder[0] === "question") + questionText.style.marginBottom = "10px"; + questionText.textContent = question; + + const inputField = document.createElement("input"); + inputField.style.display = this.isInputEnabled ? "block" : "none"; + inputField.style.fontSize = this.fontSize; + inputField.style.margin = "0 auto"; + inputField.type = this.isInputEnabled.toLowerCase(); + inputField.addEventListener("input", () => { + this.userInput = inputField.value; + }); + const buttonContainer = document.createElement("div"); + buttonContainer.classList.add("button-container"); + for (const buttonName in this.buttonJSON) { + const buttonInfo = this.buttonJSON[buttonName]; + if (buttonInfo.name.includes("")) { + const lineBreak = document.createElement("br"); + buttonContainer.appendChild(lineBreak); + } else { + const button = document.createElement("button"); + if (this.uiOrder[0] !== "buttons") + button.style.marginTop = "10px"; + if (this.uiOrder[2] !== "buttons") + button.style.marginBottom = "10px"; + button.style.marginRight = "5px"; + button.style.cursor = "pointer"; + button.textContent = buttonInfo.name; + button.style.display = "inline-block"; + button.addEventListener("click", () => { + this.lastPressBtn = buttonInfo.name; + this.userInput = + this.isInputEnabled === "Disabled" + ? buttonInfo.name + : inputField.value; + this.closeOverlay(overlay); + resolve(); + }); + buttonContainer.appendChild(button); + } + } + + const dropdown = document.createElement("div"); + dropdown.className = "dropdown"; + const dropdownButton = document.createElement("button"); + dropdownButton.className = "dropbtn"; + dropdownButton.textContent = this.DropdownText; + const dropdownContent = document.createElement("div"); + dropdownContent.id = "myDropdown"; + dropdownContent.className = "dropdown-content"; + dropdownContent.style.display = "none"; + + const optionLabels = this.optionList; + optionLabels.forEach((label, index) => { + const optionLabel = document.createElement("label"); + optionLabel.style.color = this.questionColor; + optionLabel.textContent = ""; + const optionRadio = document.createElement("input"); + optionRadio.type = + this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; + optionRadio.name = "dropdownOptions"; + optionRadio.value = index; + optionRadio.classList.add("dropdown-radio"); + optionRadio.addEventListener("click", () => { + if (this.isInputEnabled === "Multi-Select Dropdown") { + if (selectedOptions.includes(label)) { + selectedOptions = selectedOptions.filter( + (item) => item !== label + ); + } else { + selectedOptions.push(label); + } + inputField.value = + selectedOptions.length > 0 + ? JSON.stringify(selectedOptions) + : ""; + } else { + inputField.value = label; + } + this.userInput = inputField.value; + }); + optionLabel.appendChild(optionRadio); + optionLabel.appendChild(document.createTextNode(" " + label)); + optionLabel.appendChild(document.createElement("br")); + dropdownContent.appendChild(optionLabel); + }); + document.body.appendChild(dropdown); + dropdownButton.addEventListener("click", () => { + this.lastPressBtn = this.DropdownText; + dropdownContent.style.display = this.isDropdownOpen + ? "none" + : "block"; + this.isDropdownOpen = !this.isDropdownOpen; + }); + + const sliderContainer = document.createElement("div"); + sliderContainer.classList.add("slider-container"); + const slider = document.createElement("input"); + if (this.isInputEnabled.includes("Vertical")) + slider.style.transform = "rotate(270deg)"; + slider.type = "range"; + slider.min = this.sliderInfo[0]; + slider.max = this.sliderInfo[1]; + slider.value = this.sliderInfo[2]; + if (this.isInputEnabled.includes("Vertical")) { + for (let i = 0; i < 3; i++) { + sliderContainer.appendChild(document.createElement("br")); + } + sliderContainer.appendChild(slider); + for (let i = 0; i < 4; i++) { + sliderContainer.appendChild(document.createElement("br")); + } + } else { + sliderContainer.appendChild(slider); + } + const valueDisplay = document.createElement("span"); + valueDisplay.classList.add("slider-value"); + sliderContainer.appendChild(valueDisplay); + valueDisplay.style.color = this.questionColor; + valueDisplay.textContent = slider.value; + slider.addEventListener("input", () => { + valueDisplay.textContent = slider.value; + this.userInput = valueDisplay.textContent; + }); + for (const item of this.uiOrder) { + switch (item) { + case "question": { + overlay.appendChild(questionText); + break; + } + case "input": + if (this.isInputEnabled !== "Disabled") { + if ( + this.isInputEnabled === "Enabled" || + this.isInputEnabled === "Color" || + this.isInputEnabled === "Number" || + this.isInputEnabled === "Password" + ) { + overlay.appendChild(inputField); + } else if (this.isInputEnabled.includes("Dropdown")) { + overlay.appendChild(dropdownButton); + overlay.appendChild(dropdownContent); + overlay.appendChild(document.createElement("br")); + } else { + overlay.appendChild(sliderContainer); + overlay.appendChild(valueDisplay); + overlay.appendChild(document.createElement("br")); + } + } + break; + case "buttons": { + overlay.appendChild(buttonContainer); + break; + } + } + } + overlay.appendChild(overlayImageContainer); + if (this.appendTarget[0] === "window") { + document.body.appendChild(overlay); + if (this.appendTarget[1]) document.body.appendChild(focusBG); + } + inputField.focus(); + inputField.value = this.defaultValue; + this.activeOverlays.push(overlay); + this.activeUI.push({ + overlay: { + button: buttonContainer, + dropdown: dropdownButton, + input: inputField, + }, + }); + if (this.appendTarget[0] === "window") { + const resizeHandler = () => { + overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; + overlay.style.top = `${this.textBoxY !== null ? 50 + this.textBoxY : 50}%`; + }; + document.addEventListener("fullscreenchange", resizeHandler); + document.addEventListener("webkitfullscreenchange", resizeHandler); + document.addEventListener("mozfullscreenchange", resizeHandler); + document.addEventListener("MSFullscreenChange", resizeHandler); + const observer = new MutationObserver((mutationsList) => { + for (const mutation of mutationsList) { + if ( + mutation.type === "childList" && + Array.from(mutation.removedNodes).includes(overlay) + ) { + document.removeEventListener( + "fullscreenchange", + resizeHandler + ); + document.removeEventListener( + "webkitfullscreenchange", + resizeHandler + ); + document.removeEventListener( + "mozfullscreenchange", + resizeHandler + ); + document.removeEventListener( + "MSFullscreenChange", + resizeHandler + ); + observer.disconnect(); + } + } + }); + observer.observe(overlay.parentNode, { childList: true }); + document.body.appendChild(overlay); + } else { + if (this.appendTarget[1]) + vm.renderer.addOverlay(focusBG, "scale-centered"); + vm.renderer.addOverlay(overlay, "scale-centered"); + } + inputField.focus(); + this.updateOverlay(overlay); + }); + } + } + closeOverlay(overlay) { + if (this.askBoxInfo[0] < 2) this.isWaitingForInput = false; + this.isDropdownOpen = false; + this.askBoxInfo[0]--; + let usedBG = document.querySelectorAll(".SP-ask-boxBG"); + usedBG = usedBG[usedBG.length - 1]; + // ^ Prioritizes Textboxes on Window + const index = this.activeOverlays.indexOf(overlay); + setTimeout(() => { + if (index !== -1) { + this.activeOverlays.splice(index, 1); + this.askBoxPromises.splice(index, 1); + } + delete this.activeUI[overlay]; + if (this.appendTarget[0] === "window") + document.body.removeChild(overlay); + else vm.renderer.removeOverlay(overlay); + if (usedBG) { + if (usedBG.id === "window") document.body.removeChild(usedBG); + else vm.renderer.removeOverlay(usedBG); + } + }, this.Timeout * 1000); + } + + setButton(args) { + if (args.BUTTON === "add") { + this.buttonJSON[args.NAME] = { + borderRadius: 5, + border: "1px none #000000", + color: "#0074D9", + textColor: "#ffffff", + name: args.NAME, + padding: "5px 10px", + image: "", + imgScale: 100, + dropShadow: "none", + outline: ["", 0], + }; + } else { + delete this.buttonJSON[args.NAME]; + } + Scratch.vm.extensionManager.refreshBlocks(); + } + + deleteAllButtons() { + this.buttonJSON = {}; + Scratch.vm.extensionManager.refreshBlocks(); + } + + lastButton() { + return this.lastPressBtn; + } + + isWaitingInput() { + return this.isWaitingForInput; + } + + isDropdown() { + return this.isDropdownOpen; + } + + setMaxBoxCount(args) { + this.askBoxInfo[1] = args.MAX; + } + + setTimeout(args) { + this.Timeout = args.TIME; + this.Condition = args.CONDITION; + } + + reportTimeout() { + return this.Timeout; + } + + getUserInput() { + return this.userInput === null ? "" : this.userInput; + } + + getBoxInfo(args) { + if (args.INFO.includes("button")) { + const buttons = Object.keys(this.buttonJSON); + return args.INFO.includes("names") + ? JSON.stringify(buttons) + : buttons.length; + } else { + return this.askBoxInfo[args.INFO === "count" ? 0 : 1]; + } + } + + setSubmitEvent(args) { + this.forceInput = args.ENTER; + } + + setDefaultV(args) { + this.defaultValue = args.defaultV; + } + + setAppend(args) { + this.appendTarget[0] = args.TARGET; + } + setFocus(args) { + this.appendTarget[1] = args.TYPE === "Enabled"; + } + + setUI(args) { + let array; + try { + array = JSON.parse(args.ARRAY.toLowerCase()); + } catch { + return; + } + if (!Array.isArray(array)) return; + const allowedUI = ["question", "input", "buttons"]; + let filteredArray = [ + ...new Set(array.filter((element) => allowedUI.includes(element))), + ]; + allowedUI.forEach((element) => { + if (!filteredArray.includes(element)) filteredArray.push(element); + }); + this.uiOrder = filteredArray; + } + + getUIOrder() { + return JSON.stringify(this.uiOrder); + } + + setEnable() { + throw new Error( + "This Block has been removed since Better Input V3. Please use the New Powerful Blocks" + ); + } + getBoxCount() { + return this.askBoxInfo[0]; + } //Legacy + getMaxCount() { + return this.askBoxInfo[1]; + } //Legacy + } + + Scratch.extensions.register(new BetterInputSP()); +})(Scratch); diff --git a/extensions/SharkPool/BetterInput.js b/extensions/SharkPool/BetterInput.js deleted file mode 100644 index 1d4083b89e..0000000000 --- a/extensions/SharkPool/BetterInput.js +++ /dev/null @@ -1,1319 +0,0 @@ -// Name: Better Input -// ID: BetterInputSP -// Description: Expansion of the "ask and wait" Blocks -// By: SharkPool - -// Version V.4.0.0 - -(function (Scratch) { - "use strict"; - if (!Scratch.extensions.unsandboxed) throw new Error("Better Input must run unsandboxed"); - - const menuIconURI = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; - - const blockIconURI = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; - - const formatIcon = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; - - const colorIcon = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; - - const effectIcon = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; - - let newColorType = ""; - let overlayImageContainer = ""; - const vm = Scratch.vm; - const fontMenu = [ - "Scratch", "Sans Serif", "Serif", - "Handwriting", "Marker", "Curly", "Pixel" - ]; - - class BetterInputSP { - constructor() { - this.activeOverlays = []; this.activeUI = []; this.askBoxPromises = []; - this.isWaitingForInput = false; this.isDropdownOpen = false; - this.userInput = " "; this.defaultValue = ""; - this.textBoxX = 0; this.textBoxY = 0; - this.askBoxInfo = [0, 1]; this.appendTarget = ["window", false]; - this.forceInput = "Disabled"; - this.overlayInput = null; - this.uiOrder = ["question", "input", "buttons"]; - - this.optionList = ["Option 1", "Option 2", "Option 3"]; - this.sliderInfo = [0, 100, 50]; - this.Timeout = 0; - - this.shadowEnabled = true; - this.isInputEnabled = "Enabled"; - this.DropdownText = "Dropdown"; - this.fontSize = "14px"; - this.textAlign = "left"; - this.fontFamily = "Sans Serif"; - // overlay + Image, input, dropdown button - this.mainUIinfo = [ - 5, 4, 5, - "1px none #000000", "1px solid #000000", "1px none #000000", - "15px", "5px", "5px 10px", - "none", "none", "none", ["", 0], ["", 0], ["", 0] - ]; - this.lastPressBtn = ""; - this.buttonJSON = { - "Submit": { - color: "#0074D9", textColor: "#ffffff", - name: "Submit", image: "", imgScale: 100, - borderRadius: 5, border: "1px none #000000", - padding: "5px 10px", dropShadow: "none", outline: ["", 0] - }, - "Cancel": { - color: "#d9534f", textColor: "#ffffff", - name: "Cancel", image: "", imgScale: 100, - borderRadius: 5, border: "1px none #000000", - padding: "5px 10px", dropShadow: "none", outline: ["", 0] - }, - }; - - this.questionColor = "#000000"; - this.inputColor = "#000000"; - this.textBoxColor = ["#ffffff"]; - this.inputFieldColor = "#ffffff"; - this.dropdownButtonColor = ["#5f5f5f", "#ffffff"]; - this.overlayImage = [" ", " ", " "]; - - this.Blur = 0; this.Brightness = 0; this.Opacity = 100; - this.Invert = 0; this.Saturation = 100; this.Hue = 0; - this.Sepia = 0; this.Contrast = 100; this.Scale = 100; - this.SkewX = 0; this.SkewY = 0; this.Rotation = 90; - this.imgScale = [100, 100, 100]; - this.shadowS = [0, 0, 5, "#000000"]; - } - - getInfo() { - return { - id: "BetterInputSP", - name: "Better Input", - color1: "#9400ff", - color2: "#7800cd", - color3: "#6900b3", - menuIconURI, - blockIconURI, - blocks: [ - { - opcode: "askAndWait", - blockType: Scratch.BlockType.COMMAND, - text: "ask [question] and wait", - arguments: { - question: { type: Scratch.ArgumentType.STRING, defaultValue: "What is your name?" } - }, - }, - { - opcode: "askAndWaitForInput", - blockType: Scratch.BlockType.REPORTER, - text: "ask [question] and wait", - arguments: { - question: { type: Scratch.ArgumentType.STRING, defaultValue: "What is your name?" } - }, - }, - { - opcode: "getUserInput", blockType: Scratch.BlockType.REPORTER, - text: "user input" - }, - { - opcode: "setDefaultV", - blockType: Scratch.BlockType.COMMAND, - text: "set default value to [defaultV]", - arguments: { - defaultV: { type: Scratch.ArgumentType.STRING, defaultValue: "My Name Is..." } - }, - }, - { - opcode: "removeAskBoxes", blockType: Scratch.BlockType.COMMAND, - text: "remove all ask boxes" - }, - { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, - { - opcode: "setEnable", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: true, text: "set [ENABLE_MENU] to be [ACTION]", - arguments: { - ENABLE_MENU: { type: Scratch.ArgumentType.STRING, menu: "enableMenu" }, - ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } - }, - }, - { - opcode: "getBoxCount", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, text: "box count" - }, - { - opcode: "getMaxCount", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, text: "box limit" - }, - { - opcode: "setFontSize", - blockType: Scratch.BlockType.COMMAND, - text: "set font size to [SIZE]", - blockIconURI: formatIcon, - arguments: { - SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 14 } - }, - }, - { - opcode: "setTextAlignment", - blockType: Scratch.BlockType.COMMAND, - text: "set alignment to [ALIGNMENT]", - blockIconURI: formatIcon, - arguments: { - ALIGNMENT: { type: Scratch.ArgumentType.STRING, menu: "alignmentMenu" } - }, - }, - { - opcode: "setFontFamily", - blockType: Scratch.BlockType.COMMAND, - text: "set font to [FONT]", - blockIconURI: formatIcon, - arguments: { - FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu" } - }, - }, - { - opcode: "setDropShadow", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] shadow to x [x] y [y] z [z] color [COLOR]", - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, - x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 2 }, - COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" } - }, - }, - { - opcode: "setOutline", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] outline to [COLOR] thickness [THICK]", - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, - COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" }, - THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } - }, - }, - "---", - { - opcode: "setInputType", - blockType: Scratch.BlockType.COMMAND, - text: "set Input Box to be [ACTION]", - blockIconURI: formatIcon, - arguments: { - ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } - }, - }, - { - opcode: "setDropdown", - blockType: Scratch.BlockType.COMMAND, - text: "set dropdown options to array: [DROPDOWN]", - blockIconURI: formatIcon, - arguments: { - DROPDOWN: { type: Scratch.ArgumentType.STRING, defaultValue: "[\"Option 1\", \"Option 2\", \"Option 3\"]" } - }, - }, - { - opcode: "setSlider", - blockType: Scratch.BlockType.COMMAND, - text: "set slider to min: [MIN] max: [MAX] default: [DEFAULT]", - blockIconURI: formatIcon, - arguments: { - MIN: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, - DEFAULT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 } - }, - }, - { blockType: Scratch.BlockType.LABEL, text: "Buttons" }, - { - opcode: "setButton", - blockType: Scratch.BlockType.COMMAND, - text: "[BUTTON] button named [NAME]", - blockIconURI: formatIcon, - arguments: { - BUTTON: { type: Scratch.ArgumentType.STRING, menu: "buttonType" }, - NAME: { type: Scratch.ArgumentType.STRING, defaultValue: "Submit" } - }, - }, - { - opcode: "deleteAllButtons", blockType: Scratch.BlockType.COMMAND, - text: "remove all buttons", blockIconURI: formatIcon - }, - { - opcode: "setButtonText", - blockType: Scratch.BlockType.COMMAND, - text: "set [BUTTON_MENU] button name to [TEXT]", - blockIconURI: formatIcon, - arguments: { - BUTTON_MENU: { type: Scratch.ArgumentType.STRING, menu: "buttonMenu" }, - TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "my dropdown" } - }, - }, - { - opcode: "lastButton", blockType: Scratch.BlockType.REPORTER, - text: "last pressed button", blockIconURI: formatIcon - }, - { blockType: Scratch.BlockType.LABEL, text: "Positioning" }, - { - opcode: "setPrePosition", - blockType: Scratch.BlockType.COMMAND, - text: "preset textbox position to x: [X] y: [Y]", - blockIconURI: formatIcon, - arguments: { - X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } - }, - }, - { - opcode: "setPosition", - blockType: Scratch.BlockType.COMMAND, - text: "set textbox position to x: [X] y: [Y]", - blockIconURI: formatIcon, - arguments: { - X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } - }, - }, - { - opcode: "changePosition", - blockType: Scratch.BlockType.COMMAND, - text: "change textbox position by x: [X] y: [Y]", - blockIconURI: formatIcon, - arguments: { - X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } - }, - }, - { - opcode: "getXpos", blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, text: "x position" - }, - { - opcode: "getYpos", blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, text: "y position" - }, - { - opcode: "setDirection", - blockType: Scratch.BlockType.COMMAND, - text: "set direction to [ROTATE]", - blockIconURI: formatIcon, - arguments: { - ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 90 } - }, - }, - { - opcode: "changeDirection", - blockType: Scratch.BlockType.COMMAND, - text: "change direction by [ROTATE]", - blockIconURI: formatIcon, - arguments: { - ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 15 } - }, - }, - { - opcode: "reportDirection", blockType: Scratch.BlockType.REPORTER, - text: "direction", blockIconURI: formatIcon - }, - { blockType: Scratch.BlockType.LABEL, text: "Visual Settings" }, - { - opcode: "setColorSettings", - blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to [COLOR]", - blockIconURI: colorIcon, - arguments: { - COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "colorSettingsMenu" }, - COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#000000" } - }, - }, - { - opcode: "setGradient", blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to gradient with [COLOR1] and [COLOR2] with direction [DIR]", - hideFromPalette: true, //deprecated but needed for support - arguments: { - COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, - DIR: { type: Scratch.ArgumentType.ANGLE } - }, - }, - { - opcode: "setCircleGradient", blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to radial gradient with [COLOR1] and [COLOR2] at x [X] y [Y]", - hideFromPalette: true, //deprecated but needed for support - arguments: { - COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, - X: { type: Scratch.ArgumentType.NUMBER }, Y: { type: Scratch.ArgumentType.NUMBER } - }, - }, - "---", - { - opcode: "setImage", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] image to [IMAGE]", - blockIconURI: colorIcon, - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - IMAGE: { type: Scratch.ArgumentType.STRING, defaultValue: "input-url-here" } - }, - }, - { - opcode: "scaleImage", - blockType: Scratch.BlockType.COMMAND, - text: "scale [ELEMENT] image to [SCALE]%", - blockIconURI: colorIcon, - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - SCALE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 } - }, - }, - "---", - { - opcode: "enableShadow", - blockType: Scratch.BlockType.COMMAND, - text: "set box shadow to be [ACTION]", - blockIconURI: colorIcon, - arguments: { - ACTION: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } - }, - }, - { - opcode: "setShadow", - blockType: Scratch.BlockType.COMMAND, - text: "set box shadow [SHADOW] to [AMT]", - blockIconURI: colorIcon, - arguments: { - SHADOW: { type: Scratch.ArgumentType.STRING, menu: "shadowStuff" }, - AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } - }, - }, - "---", - { - opcode: "setBorder", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] border to [TYPE] color [COLOR] width [WIDTH]", - blockIconURI: colorIcon, - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - TYPE: { type: Scratch.ArgumentType.STRING, menu: "borderTypes" }, - COLOR: { type: Scratch.ArgumentType.COLOR }, - WIDTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - }, - }, - { - opcode: "setBorderRadius", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] border radius to [VALUE]", - blockIconURI: colorIcon, - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - VALUE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - }, - }, - { - opcode: "setPadding", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] padding to T: [N1] B: [N3] L: [N4] R: [N2]", - blockIconURI: colorIcon, - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - N1: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - N2: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - N3: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - N4: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } - }, - }, - { blockType: Scratch.BlockType.LABEL, text: "Effects" }, - { - opcode: "resetEffect", - blockType: Scratch.BlockType.COMMAND, - text: "reset effects", - blockIconURI: effectIcon - }, - { - opcode: "setEffect", - blockType: Scratch.BlockType.COMMAND, - text: "set effect [EFFECT] to [AMT]", - blockIconURI: effectIcon, - arguments: { - EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, - AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - }, - }, - { - opcode: "changeEffect", - blockType: Scratch.BlockType.COMMAND, - text: "change effect [EFFECT] by [AMT]", - blockIconURI: effectIcon, - arguments: { - EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, - AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } - }, - }, - { - opcode: "showEffect", - blockType: Scratch.BlockType.REPORTER, - text: "effect [EFFECT]", - blockIconURI: effectIcon, - arguments: { - EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" } - }, - }, - "---", - { - opcode: "setTimeout", - blockType: Scratch.BlockType.COMMAND, - text: "when submitted delete textbox after [TIME] secs", - blockIconURI: effectIcon, - arguments: { - TIME: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } - }, - }, - { - opcode: "reportTimeout", - blockType: Scratch.BlockType.REPORTER, - text: "current textbox timeout", - blockIconURI: effectIcon - }, - { blockType: Scratch.BlockType.LABEL, text: "Operations" }, - { - opcode: "setUI", - blockType: Scratch.BlockType.COMMAND, - text: "set UI order to [ARRAY]", - arguments: { - ARRAY: { type: Scratch.ArgumentType.STRING, defaultValue: "[\"question\", \"input\", \"buttons\"]" } - }, - }, - { - opcode: "getUIOrder", - blockType: Scratch.BlockType.REPORTER, - text: "UI order" - }, - "---", - { - opcode: "setAppend", - blockType: Scratch.BlockType.COMMAND, - text: "append next textbox to [TARGET]", - arguments: { - TARGET: { type: Scratch.ArgumentType.STRING, menu: "appendMenu" } - }, - }, - { - opcode: "setFocus", - blockType: Scratch.BlockType.COMMAND, - text: "toggle focus mode to [TYPE]", - arguments: { - TYPE: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } - }, - }, - "---", - { - opcode: "isWaitingInput", - blockType: Scratch.BlockType.BOOLEAN, - text: "is waiting?" - }, - { - opcode: "isDropdown", - blockType: Scratch.BlockType.BOOLEAN, - text: "is dropdown open?" - }, - { - opcode: "setSubmitEvent", - blockType: Scratch.BlockType.COMMAND, - text: "set force input to [ENTER]", - arguments: { - ENTER: { type: Scratch.ArgumentType.STRING, menu: "enterMenu" } - }, - }, - { - opcode: "setMaxBoxCount", - blockType: Scratch.BlockType.COMMAND, - text: "set max box count to: [MAX]", - arguments: { - MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 } - }, - }, - { - opcode: "getBoxInfo", - blockType: Scratch.BlockType.REPORTER, - text: "textbox [INFO]", - arguments: { - INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo" } - }, - }, - ], - menus: { - enableMenu: { acceptReporters: true, items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"] }, - // ^ Old Menu ^ (Needed for V2 Support) - fontMenu: { acceptReporters: true, items: "allFonts" }, - buttonMenu: { - acceptReporters: true, - items: this.allButtons(["Dropdown"], false), - }, - elementMenu: { - acceptReporters: true, - items: this.allButtons(["Textbox", "Input Box", "Dropdown Button"], false), - }, - colorSettingsMenu: { - acceptReporters: true, - items: this.allButtons([ - "Textbox", "Question Text", "Textbox Shadow", - "Input Text", "Input Box", - "Dropdown Button", "Dropdown Text" - ], true), - }, - textsMenu: { - acceptReporters: true, - items: this.allButtons(["Question Text", "Input Text", "Dropdown Text"], true, true), - }, - appendMenu: ["window", "canvas"], - buttonType: { acceptReporters: true, items: ["add", "remove"] }, - buttonActionMenu: { acceptReporters: true, items: ["Enabled", "Disabled"] }, - alignmentMenu: { acceptReporters: true, items: ["left", "right", "center"] }, - shadowStuff: { acceptReporters: true, items: ["Size", "X", "Y"] }, - boxInfo: { - acceptReporters: true, - items: ["count", "limit", "button count", "button names"], - }, - inputActionMenu: { - acceptReporters: true, - items: [ - "None", "Text", "Password", "Number", "Color", - "Dropdown", "Multi-Select Dropdown", - "Horizontal Slider", "Vertical Slider" - ], - }, - effectMenu: { - acceptReporters: true, - items: [ - "Blur", "Brightness", "Opacity", - "Invert", "Saturation", "Hue", - "Sepia", "Contrast", - "Scale", "SkewX", "SkewY", - ], - }, - enterMenu: { - acceptReporters: true, - items: ["Disabled", "Enter Key", "Shift + Enter Key"], - }, - borderTypes: { - acceptReporters: true, - items: [ - "none", "solid", "dotted", "dashed", - "double", "groove", "ridge", "inset", "outset" - ], - } - }, - }; - } - - allFonts() { - const customFonts = Scratch.vm.runtime.fontManager - ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({ - text: i.name, value: i.family - })) - : []; - return [ ...fontMenu, ...customFonts ]; - } - - allButtons(array, enableTxt, justTxt) { - let customBtn = Object.keys(this.buttonJSON); - if (justTxt) customBtn = customBtn.map(btn => btn + " Text"); - else if (enableTxt) customBtn.forEach((btn) => { customBtn.push(btn + " Text") }); - return [ ...array, ...customBtn ]; - } - - updateOverlayPos(overlay) { - if (this.Rotation > 359) this.Rotation = 0; - else if (this.Rotation < 1) this.Rotation = 360; - if (this.textBoxX !== null && this.textBoxY !== null) { - if (this.appendTarget[0] === "window") { - overlay.style.left = `${50 + this.textBoxX}%`; - overlay.style.top = `${50 + this.textBoxY}%`; - } - overlay.style.transform = ` - translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)` } - SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) - rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) - `; - } else { - overlay.style.left = "50%"; - overlay.style.top = "50%"; - } - } - updateOverlay(overlay) { - const newOpacity = this.Opacity / 100; - const newBrightness = this.Brightness + 100; - overlay.style.backgroundImage = ""; - overlay.style[this.textBoxColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.textBoxColor[0]; - overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px ${this.shadowS[3]}` : "none"; - overlay.style.transform = ` - translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)` } - SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) - rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) - `; - overlay.style.filter = ` - blur(${this.Blur}px) brightness(${newBrightness}%) - invert(${this.Invert}%) saturate(${this.Saturation}%) - hue-rotate(${this.Hue}deg) sepia(${this.Sepia}%) - contrast(${this.Contrast}%) - `; - overlay.style.opacity = newOpacity; - overlay.style.border = this.mainUIinfo[3]; - overlay.style.padding = this.mainUIinfo[6]; - overlay.style.fontFamily = this.fontFamily; - overlay.style.textAlign = this.textAlign; - overlay.style.borderRadius = `${this.mainUIinfo[0]}px`; - overlayImageContainer.style.borderRadius = `${this.mainUIinfo[0]}px`; - overlayImageContainer.style.background = ""; - this.setImageStyles(overlayImageContainer, this.overlayImage[0], this.imgScale[0]); - this.updateButtonImages(overlay); - } - updateButtonImages(overlay) { - let text = overlay.querySelector(".question"); - if (text) { - text.style.color = this.questionColor; - text.style.textShadow = this.mainUIinfo[9]; - this.tryOutline(text, this.mainUIinfo[12][0], this.mainUIinfo[12][1]); - } - const inputField = overlay.querySelector("input"); - if (inputField) { - inputField.style.width = this.isInputEnabled === "Color" ? "100%" : "auto"; - inputField.style.background = ""; - inputField.style.fontFamily = this.fontFamily; - inputField.style[this.inputFieldColor.includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.inputFieldColor; - inputField.style.color = this.inputColor; - inputField.style.textShadow = this.mainUIinfo[10]; - this.tryOutline(inputField, this.mainUIinfo[13][0], this.mainUIinfo[13][1]); - inputField.style.border = this.mainUIinfo[4]; - inputField.style.borderRadius = `${this.mainUIinfo[1]}px`; - inputField.style.padding = this.mainUIinfo[7]; - this.setImageStyles(inputField, this.overlayImage[1], this.imgScale[1]); - } - - const dropBtn = overlay.querySelector("button.dropbtn"); - if (dropBtn) { - dropBtn.style.backgroundImage = ""; - dropBtn.style.fontFamily = this.fontFamily; - dropBtn.style.color = this.dropdownButtonColor[1]; - dropBtn.style.borderRadius = `${this.mainUIinfo[2]}px`; - dropBtn.style.border = this.mainUIinfo[5]; - dropBtn.style.padding = this.mainUIinfo[8]; - dropBtn.style.textShadow = this.mainUIinfo[11]; - this.tryOutline(dropBtn, this.mainUIinfo[14][0], this.mainUIinfo[14][1]); - dropBtn.style[this.dropdownButtonColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdownButtonColor[0]; - this.setImageStyles(dropBtn, this.overlayImage[2], this.imgScale[2]); - } - const buttonContainer = overlay.querySelector(".button-container"); - if (buttonContainer) { - const buttons = buttonContainer.querySelectorAll("button"); - buttons.forEach((button, index) => { - const buttonName = Object.keys(this.buttonJSON)[index]; - const buttonInfo = this.buttonJSON[buttonName]; - if (buttonInfo) { - button.style.color = buttonInfo.textColor; - button.style.fontFamily = this.fontFamily; - button.style.borderRadius = `${buttonInfo.borderRadius}px`; - button.style.border = buttonInfo.border; - button.style.padding = buttonInfo.padding; - button.style.textShadow = buttonInfo.dropShadow; - this.tryOutline(button, buttonInfo.outline[0], buttonInfo.outline[1]); - button.style.background = ""; - button.style[buttonInfo.color.includes("gradient") ? "backgroundImage" : "background"] = buttonInfo.color; - this.setImageStyles(button, buttonInfo.image, buttonInfo.imgScale); - } - }); - } - } - tryOutline(element, color, thick) { - element.style.webkitTextStrokeColor = color; - element.style.webkitTextStrokeWidth = `${thick}px`; - //multi-platform support cuz we cant have nice things - element.style.textStrokeColor = color; - element.style.textStrokeWidth = `${thick}px`; - element.style.mozTextStrokeColor = color; - element.style.mozTextStrokeWidth = `${thick}px`; - } - - setImageStyles(element, url, scale) { - if (Scratch.Cast.toString(url).length > 5) { - Scratch.canFetch(encodeURI(url)).then((canFetch) => { - if (canFetch) { - element.style.background = `url(${encodeURI(url)})`; - element.style.backgroundSize = `${scale}%`; - } else { console.log("Cannot fetch content from the URL") } - }); - } - } - - showEffect(args) { return this[args.EFFECT] } - - setEffect(args) { - this[args.EFFECT] = args.AMT; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - changeEffect(args) { - const effect = args.EFFECT; - this[effect] = this[effect] + args.AMT; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - resetEffect() { - this.Blur = 0; this.Brightness = 0; this.Opacity = 100; this.Invert = 0; - this.Saturation = 100; this.Hue = 0; this.Sepia = 0; this.Contrast = 100; - this.Scale = 100; this.SkewX = 0; this.SkewY = 0; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - setColorSettings(args) { - const colorType = args.COLOR_TYPE; - const colorValue = args.COLOR; - const colorTypeMap = { - "Question Text": () => this.questionColor = colorValue, - "Input Text": () => this.inputColor = colorValue, - "Textbox": () => { this.textBoxColor[0] = colorValue; this.overlayImage[0] = " "; }, - "Textbox Shadow": () => { this.shadowS[3] = colorValue }, - "Input Box": () => { this.inputFieldColor = colorValue; this.overlayImage[1] = " "; }, - "Dropdown Button": () => { this.dropdownButtonColor[0] = colorValue; this.overlayImage[2] = " "; }, - "Dropdown Text": () => this.dropdownButtonColor[1] = colorValue, - }; - const buttonInfo = this.buttonJSON[colorType] || this.buttonJSON[colorType.replace(" Text", "")]; - if (buttonInfo) { - if (colorType.includes(" Text")) { - buttonInfo.textColor = colorValue; - } else { - buttonInfo.color = colorValue; - buttonInfo.image = " "; - } - } - const applyColor = colorTypeMap[colorType]; - if (applyColor) applyColor(); - this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); - } - - findGradientType(menu) { - const colorTypeMap = { - Textbox: { newColorType: "textBoxColor", ind: 0 }, - "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 } - }; - if (colorTypeMap[menu]) { - const { newColorType, ind } = colorTypeMap[menu]; - this.overlayImage[ind] = " "; - return newColorType; - } else if (this.buttonJSON[menu]) { return ["button", menu] } - return menu; - } - - setGradient(args) { - if (args.COLOR_TYPE === "Input Box") throw new Error ("As of Better Input V4, this Option no Longer Works"); - const newColorType = this.findGradientType(args.COLOR_TYPE); - const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; - if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; - else this.buttonJSON[newColorType[1]].color = gradientColor; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - setCircleGradient(args) { - const newColorType = this.findGradientType(args.COLOR_TYPE); - const newPos = [args.X + 50, args.Y + 50]; - const gradientColor = `radial-gradient(circle at ${newPos[0]}% ${newPos[1]}%, ${args.COLOR2}, ${args.COLOR1})`; - if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; - else this.buttonJSON[newColorType[1]].color = gradientColor; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - callStyling(element, value, type, elements) { - const elementIndex = elements[element]; - if (elementIndex !== undefined) this.mainUIinfo[elementIndex] = value; - else if (this.buttonJSON[element]) this.buttonJSON[element][type] = value; - this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); - } - - setBorder(args) { - const width = Scratch.Cast.toNumber(args.WIDTH); - const string = `${width}px ${args.TYPE} ${args.COLOR}`; - this.callStyling( - args.ELEMENT, string, "border", - { Textbox: 3, "Input Box": 4, "Dropdown Button": 5 } - ); - } - - setBorderRadius(args) { - this.callStyling( - args.ELEMENT, Math.max(args.VALUE, 0), "borderRadius", - { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 } - ); - } - - setPadding(args) { - const casted = [ - Scratch.Cast.toNumber(args.N1), Scratch.Cast.toNumber(args.N2), - Scratch.Cast.toNumber(args.N3), Scratch.Cast.toNumber(args.N4) - ]; - let pad = `${casted[0]}px ${casted[1]}px ${casted[2]}px ${casted[3]}px`; - this.callStyling( - args.ELEMENT, pad, "padding", - { Textbox: 6, "Input Box": 7, "Dropdown Button": 8 } - ); - } - - setDropShadow(args) { - const casted = [ - Scratch.Cast.toNumber(args.x), Scratch.Cast.toNumber(args.y), - Scratch.Cast.toNumber(args.z), - ]; - let shadow = args.z === 0 ? "none" : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; - this.callStyling( - args.ELEMENT.slice(0, -5), shadow, "dropShadow", - { "Question": 9, "Input": 10, "Dropdown": 11 } - ); - } - - setOutline(args) { - const thick = Scratch.Cast.toNumber(args.THICK); - this.callStyling( - args.ELEMENT.slice(0, -5), [args.COLOR, thick], "outline", - { "Question": 12, "Input": 13, "Dropdown": 14 } - ); - } - - setShadow(args) { - const shadowMap = { Size: 2, X: 0, Y: 1 }; - const propertyIndex = shadowMap[args.SHADOW]; - if (propertyIndex !== undefined) this.shadowS[propertyIndex] = args.AMT; - this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); - } - - setImage(args) { - const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; - const elementIndex = elementMap[args.ELEMENT]; - if (elementIndex !== undefined) this.overlayImage[elementIndex] = args.IMAGE; - else if (this.buttonJSON[args.ELEMENT]) this.buttonJSON[args.ELEMENT].image = args.IMAGE; - this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); - } - - scaleImage(args) { - const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; - const elementIndex = elementMap[args.ELEMENT]; - if (elementIndex !== undefined) this.imgScale[elementIndex] = args.SCALE; - else if (this.buttonJSON[args.ELEMENT]) this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; - this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); - } - - setDirection(args) { - this.Rotation = Scratch.Cast.toNumber(args.ROTATE); - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - changeDirection(args) { - this.Rotation = this.Rotation + Scratch.Cast.toNumber(args.ROTATE); - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - reportDirection() { return this.Rotation } - - setPrePosition(args) { - this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); - this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - } - - setPosition(args) { - this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); - this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay) }); - } - - changePosition(args) { - this.textBoxX = this.textBoxX + Scratch.Cast.toNumber(args.X) / (screen.width / 400); - this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay) }); - } - - getXpos() { return this.textBoxX * (screen.width / 400) } - getYpos() { return this.textBoxY * (screen.height / -300) } - - setFontSize(args) { this.fontSize = args.SIZE + "px" } - - setTextAlignment(args) { - this.textAlign = args.ALIGNMENT; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - setFontFamily(args) { - this.fontFamily = args.FONT; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - - setSlider(args) { this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT] } - - setInputType(args) { - if (args.ACTION === "Text" || args.ACTION === "None") { - this.isInputEnabled = args.ACTION === "Text" ? "Enabled" : "Disabled"; - } else { this.isInputEnabled = args.ACTION } - } - - enableShadow(args) { this.shadowEnabled = args.ACTION === "Enabled" } - - setButtonText(args) { - const buttonMenu = args.BUTTON_MENU; - const text = args.TEXT; - if (buttonMenu === "Dropdown") { - this.DropdownText = text; - } else if (this.buttonJSON[buttonMenu]) { - this.buttonJSON[buttonMenu].name = text; - Scratch.vm.extensionManager.refreshBlocks(); - } - } - - setDropdown(args) { - try { - this.optionList = JSON.parse(args.DROPDOWN); - } catch { this.optionList = ["Undefined Array Error"] } - } - - removeAskBoxes() { - const overlaysToRemove = []; - this.activeOverlays.forEach((overlay) => { - if (overlay) { - if (this.appendTarget[0] === "window" && overlay.parentNode) { - overlay.parentNode.removeChild(overlay); - } else if (overlay.parentNode.parentNode !== document.documentElement) { - overlay.parentNode.parentNode.removeChild(overlay.parentNode); - } - overlaysToRemove.push(overlay); - } - if (this.askBoxPromises) { - const index = this.activeOverlays.indexOf(overlay); - if (index !== -1) this.askBoxPromises[index].resolve("removed"); - } - }); - this.askBoxPromises = []; - this.activeOverlays = this.activeOverlays.filter((overlay) => !overlaysToRemove.includes(overlay)); - this.activeUI = []; - this.askBoxInfo[0] = 0; - // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info - const bugged = document.querySelectorAll(`[class^="SP-ask-box"]`); - bugged.forEach((box) => { box.parentNode.removeChild(box) }); - } - - askAndWaitForInput(args) { - if (this.askBoxInfo[0] < this.askBoxInfo[1] ) { - return this.askAndWait(args).then(() => { return this.getUserInput() }); - } - } - - askAndWait(args) { - if (this.askBoxInfo[0] < this.askBoxInfo[1]) { - const question = args.question; - this.isWaitingForInput = true; - this.lastPressBtn = ""; - this.askBoxInfo[0]++; - let selectedOptions = []; - return new Promise((resolve) => { - const askBoxPromise = { resolve }; - this.askBoxPromises.push(askBoxPromise); - const overlay = document.createElement("div"); - overlay.classList.add("SP-ask-box"); - overlay.style.pointerEvents = "auto"; - overlay.style.position = "fixed"; - overlay.style.zIndex = "9999"; - overlay.style.fontSize = this.fontSize; - overlay.style.left = this.appendTarget[0] === "window" ? `${50 + this.textBoxX}%` : "0%"; - overlay.style.top = this.appendTarget[0] === "window" ? `${50 + this.textBoxY}%` : "0%"; - - const focusBG = document.createElement("div"); - focusBG.style.cssText = "pointer-events: auto; position: fixed; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 9998;"; - focusBG.className = "SP-ask-boxBG"; - focusBG.id = this.appendTarget[0]; - focusBG.style.left = this.appendTarget[0] === "window" ? "0%" : "-50%"; - focusBG.style.top = this.appendTarget[0] === "window" ? "0%" : "-50%"; - - overlayImageContainer = document.createElement("div"); - overlayImageContainer.style.width = "100%"; - overlayImageContainer.style.height = "100%"; - overlayImageContainer.style.position = "absolute"; - overlayImageContainer.style.top = 0; - overlayImageContainer.style.left = 0; - overlayImageContainer.style.zIndex = "-1"; - if (this.forceInput !== "Disabled") { - const overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; - const handleKeydown = (event) => { - if ((overlayInput === "ShiftEnter" && event.shiftKey && event.key === "Enter") || event.key === overlayInput) { - this.userInput = inputField.value; - this.closeOverlay(overlay); - resolve(); - } - }; - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === "childList" && !document.contains(overlay)) { - document.removeEventListener("keydown", handleKeydown); - observer.disconnect(); - } - } - }); - observer.observe(document.body, { childList: true }); - document.addEventListener("keydown", handleKeydown); - } - - const questionText = document.createElement("div"); - questionText.classList.add("question"); - questionText.style.fontSize = this.fontSize; - if (this.uiOrder[0] !== "question") questionText.style.marginTop = "10px"; - if (this.uiOrder[0] === "question") questionText.style.marginBottom = "10px"; - questionText.textContent = question; - - const inputField = document.createElement("input"); - inputField.style.display = this.isInputEnabled ? "block" : "none"; - inputField.style.fontSize = this.fontSize; - inputField.style.margin = "0 auto"; - inputField.type = this.isInputEnabled.toLowerCase(); - inputField.addEventListener("input", () => { this.userInput = inputField.value }); - const buttonContainer = document.createElement("div"); - buttonContainer.classList.add("button-container"); - for (const buttonName in this.buttonJSON) { - const buttonInfo = this.buttonJSON[buttonName]; - if (buttonInfo.name.includes("")) { - const lineBreak = document.createElement("br"); - buttonContainer.appendChild(lineBreak); - } else { - const button = document.createElement("button"); - if (this.uiOrder[0] !== "buttons") button.style.marginTop = "10px"; - if (this.uiOrder[2] !== "buttons") button.style.marginBottom = "10px"; - button.style.marginRight = "5px"; - button.style.cursor = "pointer"; - button.textContent = buttonInfo.name; - button.style.display = "inline-block"; - button.addEventListener("click", () => { - this.lastPressBtn = buttonInfo.name; - this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; - this.closeOverlay(overlay); - resolve(); - }); - buttonContainer.appendChild(button); - } - } - - const dropdown = document.createElement("div"); - dropdown.className = "dropdown"; - const dropdownButton = document.createElement("button"); - dropdownButton.className = "dropbtn"; - dropdownButton.textContent = this.DropdownText; - const dropdownContent = document.createElement("div"); - dropdownContent.id = "myDropdown"; - dropdownContent.className = "dropdown-content"; - dropdownContent.style.display = "none"; - - const optionLabels = this.optionList; - optionLabels.forEach((label, index) => { - const optionLabel = document.createElement("label"); - optionLabel.style.color = this.questionColor; - optionLabel.textContent = ""; - const optionRadio = document.createElement("input"); - optionRadio.type = this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; - optionRadio.name = "dropdownOptions"; - optionRadio.value = index; - optionRadio.classList.add("dropdown-radio"); - optionRadio.addEventListener("click", () => { - if (this.isInputEnabled === "Multi-Select Dropdown") { - if (selectedOptions.includes(label)) { - selectedOptions = selectedOptions.filter(item => item !== label); - } else { selectedOptions.push(label) } - inputField.value = selectedOptions.length > 0 ? JSON.stringify(selectedOptions) : ""; - } else { inputField.value = label } - this.userInput = inputField.value; - }); - optionLabel.appendChild(optionRadio); - optionLabel.appendChild(document.createTextNode(" " + label)); - optionLabel.appendChild(document.createElement("br")); - dropdownContent.appendChild(optionLabel); - }); - document.body.appendChild(dropdown); - dropdownButton.addEventListener("click", () => { - this.lastPressBtn = this.DropdownText; - dropdownContent.style.display = this.isDropdownOpen ? "none" : "block"; - this.isDropdownOpen = !this.isDropdownOpen; - }); - - const sliderContainer = document.createElement("div"); - sliderContainer.classList.add("slider-container"); - const slider = document.createElement("input"); - if (this.isInputEnabled.includes("Vertical")) slider.style.transform = "rotate(270deg)"; - slider.type = "range"; - slider.min = this.sliderInfo[0]; - slider.max = this.sliderInfo[1]; - slider.value = this.sliderInfo[2]; - if (this.isInputEnabled.includes("Vertical")) { - for (let i = 0; i < 3; i++) { sliderContainer.appendChild(document.createElement("br")) } - sliderContainer.appendChild(slider); - for (let i = 0; i < 4; i++) { sliderContainer.appendChild(document.createElement("br")) } - } else { sliderContainer.appendChild(slider) } - const valueDisplay = document.createElement("span"); - valueDisplay.classList.add("slider-value"); - sliderContainer.appendChild(valueDisplay); - valueDisplay.style.color = this.questionColor; - valueDisplay.textContent = slider.value; - slider.addEventListener("input", () => { - valueDisplay.textContent = slider.value; - this.userInput = valueDisplay.textContent; - }); - for (const item of this.uiOrder) { - switch (item) { - case "question": { overlay.appendChild(questionText); break } - case "input": - if (this.isInputEnabled !== "Disabled") { - if (this.isInputEnabled === "Enabled" || this.isInputEnabled === "Color" || - this.isInputEnabled === "Number" || this.isInputEnabled === "Password" - ) { - overlay.appendChild(inputField); - } else if (this.isInputEnabled.includes("Dropdown")) { - overlay.appendChild(dropdownButton); - overlay.appendChild(dropdownContent); - overlay.appendChild(document.createElement("br")); - } else { - overlay.appendChild(sliderContainer); - overlay.appendChild(valueDisplay); - overlay.appendChild(document.createElement("br")); - } - } - break; - case "buttons": { overlay.appendChild(buttonContainer); break } - } - } - overlay.appendChild(overlayImageContainer); - if (this.appendTarget[0] === "window") { - document.body.appendChild(overlay); - if (this.appendTarget[1]) document.body.appendChild(focusBG); - } - inputField.focus(); - inputField.value = this.defaultValue; - this.activeOverlays.push(overlay); - this.activeUI.push({ overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField } }); - if (this.appendTarget[0] === "window") { - const resizeHandler = () => { - overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; - overlay.style.top = `${this.textBoxY !== null ? 50 + this.textBoxY : 50}%`; - }; - document.addEventListener("fullscreenchange", resizeHandler); - document.addEventListener("webkitfullscreenchange", resizeHandler); - document.addEventListener("mozfullscreenchange", resizeHandler); - document.addEventListener("MSFullscreenChange", resizeHandler); - const observer = new MutationObserver((mutationsList) => { - for (const mutation of mutationsList) { - if (mutation.type === "childList" && Array.from(mutation.removedNodes).includes(overlay)) { - document.removeEventListener("fullscreenchange", resizeHandler); - document.removeEventListener("webkitfullscreenchange", resizeHandler); - document.removeEventListener("mozfullscreenchange", resizeHandler); - document.removeEventListener("MSFullscreenChange", resizeHandler); - observer.disconnect(); - } - } - }); - observer.observe(overlay.parentNode, { childList: true }); - document.body.appendChild(overlay); - } else { - if (this.appendTarget[1]) vm.renderer.addOverlay(focusBG, "scale-centered"); - vm.renderer.addOverlay(overlay, "scale-centered"); - } - inputField.focus(); - this.updateOverlay(overlay); - }); - } - } - closeOverlay(overlay) { - if (this.askBoxInfo[0] < 2) this.isWaitingForInput = false; - this.isDropdownOpen = false; - this.askBoxInfo[0]--; - let usedBG = document.querySelectorAll(".SP-ask-boxBG"); - usedBG = usedBG[usedBG.length - 1]; - // ^ Prioritizes Textboxes on Window - const index = this.activeOverlays.indexOf(overlay); - setTimeout(() => { - if (index !== -1) { - this.activeOverlays.splice(index, 1); - this.askBoxPromises.splice(index, 1); - } - delete this.activeUI[overlay]; - if (this.appendTarget[0] === "window") document.body.removeChild(overlay); - else vm.renderer.removeOverlay(overlay); - if (usedBG) { - if (usedBG.id === "window") document.body.removeChild(usedBG); - else vm.renderer.removeOverlay(usedBG); - } - }, this.Timeout * 1000); - } - - setButton(args) { - if (args.BUTTON === "add") { - this.buttonJSON[args.NAME] = { - borderRadius: 5, border: "1px none #000000", - color: "#0074D9", textColor: "#ffffff", - name: args.NAME, padding: "5px 10px", - image: "", imgScale: 100, - dropShadow: "none", outline: ["", 0] - }; - } else { delete this.buttonJSON[args.NAME] } - Scratch.vm.extensionManager.refreshBlocks(); - } - - deleteAllButtons() { - this.buttonJSON = {}; - Scratch.vm.extensionManager.refreshBlocks(); - } - - lastButton() { return this.lastPressBtn } - - isWaitingInput() { return this.isWaitingForInput } - - isDropdown() { return this.isDropdownOpen } - - setMaxBoxCount(args) { this.askBoxInfo[1] = args.MAX } - - setTimeout(args) { - this.Timeout = args.TIME; - this.Condition = args.CONDITION; - } - - reportTimeout() { return this.Timeout } - - getUserInput() { return this.userInput === null ? "" : this.userInput } - - getBoxInfo(args) { - if (args.INFO.includes("button")) { - const buttons = Object.keys(this.buttonJSON); - return args.INFO.includes("names") ? JSON.stringify(buttons) : buttons.length; - } else { return this.askBoxInfo[args.INFO === "count" ? 0 : 1] } - } - - setSubmitEvent(args) { this.forceInput = args.ENTER } - - setDefaultV(args) { this.defaultValue = args.defaultV } - - setAppend(args) { this.appendTarget[0] = args.TARGET } - setFocus(args) { this.appendTarget[1] = args.TYPE === "Enabled" } - - setUI(args) { - let array; - try { array = JSON.parse(args.ARRAY.toLowerCase()) } catch { return } - if (!Array.isArray(array)) return; - const allowedUI = ["question", "input", "buttons"]; - let filteredArray = [...new Set(array.filter(element => allowedUI.includes(element)))]; - allowedUI.forEach(element => { - if (!filteredArray.includes(element)) filteredArray.push(element); - }); - this.uiOrder = filteredArray; - } - - getUIOrder() { return JSON.stringify(this.uiOrder) } - - setEnable() { throw new Error("This Block has been removed since Better Input V3. Please use the New Powerful Blocks") } - getBoxCount() { return this.askBoxInfo[0] } //Legacy - getMaxCount() { return this.askBoxInfo[1] } //Legacy - } - - Scratch.extensions.register(new BetterInputSP()); -})(Scratch); diff --git a/extensions/extensions.json b/extensions/extensions.json index 58a0294d03..d872c652da 100644 --- a/extensions/extensions.json +++ b/extensions/extensions.json @@ -56,6 +56,7 @@ "Lily/Cast", "-SIPC-/time", "-SIPC-/consoles", + "SharkPool/Better-Input", "ZXMushroom63/searchApi", "TheShovel/ShovelUtils", "Lily/Assets", From 86168cf0c1642c2f655bc4f2c61e1139ffb987a3 Mon Sep 17 00:00:00 2001 From: Muffin Date: Fri, 23 Feb 2024 22:47:06 -0600 Subject: [PATCH 30/46] unused variable --- extensions/SharkPool/Better-Input.js | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index f012c21251..1dcaf8fe7e 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -25,7 +25,6 @@ const effectIcon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; - let newColorType = ""; let overlayImageContainer = ""; const vm = Scratch.vm; const fontMenu = [ From becbaf98f006fa2f3ffcf8740a4e74095d6357aa Mon Sep 17 00:00:00 2001 From: Muffin Date: Fri, 23 Feb 2024 22:47:23 -0600 Subject: [PATCH 31/46] that font doesnt exist anymore --- extensions/SharkPool/Better-Input.js | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 1dcaf8fe7e..f5e45d0907 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -28,7 +28,6 @@ let overlayImageContainer = ""; const vm = Scratch.vm; const fontMenu = [ - "Scratch", "Sans Serif", "Serif", "Handwriting", From 2878d36c18c2125d64f44b8e4b8a9c67ebb8ad93 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Thu, 29 Feb 2024 20:53:27 -0800 Subject: [PATCH 32/46] Smol bug fix --- extensions/SharkPool/Better-Input.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index f5e45d0907..85f1c6f683 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -3,7 +3,7 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.4.0.0 +// Version V.4.0.1 (function (Scratch) { "use strict"; @@ -1522,6 +1522,7 @@ valueDisplay.textContent = slider.value; slider.addEventListener("input", () => { valueDisplay.textContent = slider.value; + inputField.value = slider.value; this.userInput = valueDisplay.textContent; }); for (const item of this.uiOrder) { From 740043dbe6f2d284fe45018a2255e3424f6ab739 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Thu, 29 Feb 2024 20:54:39 -0800 Subject: [PATCH 33/46] Update Better-Input.js --- extensions/SharkPool/Better-Input.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 85f1c6f683..9eaaebf2f5 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -1,6 +1,6 @@ // Name: Better Input // ID: BetterInputSP -// Description: Expansion of the "ask and wait" Blocks +// Description: Expansion of the "ask and wait" Blocks. // By: SharkPool // Version V.4.0.1 From 4656c6296ff60880dfcf52ca575c6c9bf471dcb0 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Thu, 29 Feb 2024 20:55:37 -0800 Subject: [PATCH 34/46] add licence --- extensions/SharkPool/Better-Input.js | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 9eaaebf2f5..45b971e6ba 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -2,6 +2,7 @@ // ID: BetterInputSP // Description: Expansion of the "ask and wait" Blocks. // By: SharkPool +// License: LGPL-3.0 // Version V.4.0.1 From 51be2e1c1f0ce3952c623a225abf85c5ca21411a Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Fri, 1 Mar 2024 18:42:14 -0800 Subject: [PATCH 35/46] Cleaner Code, Better-Input.js --- extensions/SharkPool/Better-Input.js | 114 ++++++++++++++------------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 45b971e6ba..d0634afc55 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -4,7 +4,7 @@ // By: SharkPool // License: LGPL-3.0 -// Version V.4.0.1 +// Version V.4.0.2 (function (Scratch) { "use strict"; @@ -64,24 +64,28 @@ this.fontSize = "14px"; this.textAlign = "left"; this.fontFamily = "Sans Serif"; - // overlay + Image, input, dropdown button - this.mainUIinfo = [ - 5, - 4, - 5, - "1px none #000000", - "1px solid #000000", - "1px none #000000", - "15px", - "5px", - "5px 10px", - "none", - "none", - "none", - ["", 0], - ["", 0], - ["", 0], - ]; + this.mainUIinfo = { + // Border Radius + overlayRad: 5, + inputRad: 4, + dropBtnRad: 5, + // Border Information + overlayBord: "1px none #000000", + inputBord: "1px solid #000000", + dropBtnBord: "1px none #000000", + // Text Padding + overlayPad: "15px", + inputPad: "5px", + dropBtnPad: "5px 10px", + // Text Shadow + overlayTxtShad: "none", + inputTxtShad: "none", + dropBtnTxtShad: "none", + // Outline: Color + Thickness + overlayOutline: ["", 0], + inputOutline: ["", 0], + dropBtnOutline: ["", 0] + }; this.lastPressBtn = ""; this.buttonJSON = { Submit: { @@ -862,12 +866,12 @@ contrast(${this.Contrast}%) `; overlay.style.opacity = newOpacity; - overlay.style.border = this.mainUIinfo[3]; - overlay.style.padding = this.mainUIinfo[6]; + overlay.style.border = this.mainUIinfo.overlayBord; + overlay.style.padding = this.mainUIinfo.overlayPad; overlay.style.fontFamily = this.fontFamily; overlay.style.textAlign = this.textAlign; - overlay.style.borderRadius = `${this.mainUIinfo[0]}px`; - overlayImageContainer.style.borderRadius = `${this.mainUIinfo[0]}px`; + overlay.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; + overlayImageContainer.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; overlayImageContainer.style.background = ""; this.setImageStyles( overlayImageContainer, @@ -880,8 +884,8 @@ let text = overlay.querySelector(".question"); if (text) { text.style.color = this.questionColor; - text.style.textShadow = this.mainUIinfo[9]; - this.tryOutline(text, this.mainUIinfo[12][0], this.mainUIinfo[12][1]); + text.style.textShadow = this.mainUIinfo.overlayTxtShad; + this.tryOutline(text, this.mainUIinfo.overlayOutline[0], this.mainUIinfo.overlayOutline[1]); } const inputField = overlay.querySelector("input"); if (inputField) { @@ -895,15 +899,15 @@ : "backgroundColor" ] = this.inputFieldColor; inputField.style.color = this.inputColor; - inputField.style.textShadow = this.mainUIinfo[10]; + inputField.style.textShadow = this.mainUIinfo.inputTxtShad; this.tryOutline( inputField, - this.mainUIinfo[13][0], - this.mainUIinfo[13][1] + this.mainUIinfo.inputOutline[0], + this.mainUIinfo.inputOutline[1] ); - inputField.style.border = this.mainUIinfo[4]; - inputField.style.borderRadius = `${this.mainUIinfo[1]}px`; - inputField.style.padding = this.mainUIinfo[7]; + inputField.style.border = this.mainUIinfo.inputBord; + inputField.style.borderRadius = `${this.mainUIinfo.inputRad}px`; + inputField.style.padding = this.mainUIinfo.inputPad; this.setImageStyles(inputField, this.overlayImage[1], this.imgScale[1]); } @@ -912,14 +916,14 @@ dropBtn.style.backgroundImage = ""; dropBtn.style.fontFamily = this.fontFamily; dropBtn.style.color = this.dropdownButtonColor[1]; - dropBtn.style.borderRadius = `${this.mainUIinfo[2]}px`; - dropBtn.style.border = this.mainUIinfo[5]; - dropBtn.style.padding = this.mainUIinfo[8]; - dropBtn.style.textShadow = this.mainUIinfo[11]; + dropBtn.style.borderRadius = `${this.mainUIinfo.dropBtnRad}px`; + dropBtn.style.border = this.mainUIinfo.dropBtnBord; + dropBtn.style.padding = this.mainUIinfo.dropBtnPad; + dropBtn.style.textShadow = this.mainUIinfo.dropBtnTxtShad; this.tryOutline( dropBtn, - this.mainUIinfo[14][0], - this.mainUIinfo[14][1] + this.mainUIinfo.dropBtnOutline[0], + this.mainUIinfo.dropBtnOutline[1] ); dropBtn.style[ this.dropdownButtonColor[0].includes("gradient") @@ -1093,27 +1097,27 @@ } callStyling(element, value, type, elements) { - const elementIndex = elements[element]; - if (elementIndex !== undefined) this.mainUIinfo[elementIndex] = value; + const elementID = elements[element]; + if (elementID !== undefined) this.mainUIinfo[elementID] = value; else if (this.buttonJSON[element]) this.buttonJSON[element][type] = value; - this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setBorder(args) { const width = Scratch.Cast.toNumber(args.WIDTH); const string = `${width}px ${args.TYPE} ${args.COLOR}`; this.callStyling(args.ELEMENT, string, "border", { - Textbox: 3, - "Input Box": 4, - "Dropdown Button": 5, + Textbox: "overlayBord", + "Input Box": "inputBord", + "Dropdown Button": "dropBtnBord" }); } setBorderRadius(args) { this.callStyling(args.ELEMENT, Math.max(args.VALUE, 0), "borderRadius", { - Textbox: 0, - "Input Box": 1, - "Dropdown Button": 2, + Textbox: "overlayRad", + "Input Box": "inputRad", + "Dropdown Button": "dropBtnRad" }); } @@ -1126,9 +1130,9 @@ ]; let pad = `${casted[0]}px ${casted[1]}px ${casted[2]}px ${casted[3]}px`; this.callStyling(args.ELEMENT, pad, "padding", { - Textbox: 6, - "Input Box": 7, - "Dropdown Button": 8, + Textbox: "overlayPad", + "Input Box": "inputPad", + "Dropdown Button": "dropBtnPad" }); } @@ -1143,9 +1147,9 @@ ? "none" : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; this.callStyling(args.ELEMENT.slice(0, -5), shadow, "dropShadow", { - Question: 9, - Input: 10, - Dropdown: 11, + "Question": "overlayTxtShad", + "Input": "inputTxtShad", + "Dropdown": "dropBtnTxtShad" }); } @@ -1155,7 +1159,11 @@ args.ELEMENT.slice(0, -5), [args.COLOR, thick], "outline", - { Question: 12, Input: 13, Dropdown: 14 } + { + "Question": "overlayOutline", + "Input": "inputOutline", + "Dropdown": "dropBtnOutline" + } ); } From dc7520337ff5a30804908b009288c69fc51126eb Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Fri, 12 Apr 2024 19:52:23 -0700 Subject: [PATCH 36/46] Update Better-Input.js --- extensions/SharkPool/Better-Input.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index d0634afc55..c0f8d9dd91 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -37,6 +37,18 @@ "Pixel", ]; + const xmlEscape = function (unsafe) { + return Scratch.Cast.toString(unsafe).replace(/[<>&'"]/g, c => { + switch (c) { + case "<": return "<"; + case ">": return ">"; + case "&": return "&"; + case "'": return "'"; + case "\"": return """; + } + }); + }; + class BetterInputSP { constructor() { this.activeOverlays = []; @@ -1411,7 +1423,7 @@ questionText.style.marginTop = "10px"; if (this.uiOrder[0] === "question") questionText.style.marginBottom = "10px"; - questionText.textContent = question; + questionText.innerHTML = xmlEscape(question).replace(/\n/g, "
"); const inputField = document.createElement("input"); inputField.style.display = this.isInputEnabled ? "block" : "none"; @@ -1436,7 +1448,7 @@ button.style.marginBottom = "10px"; button.style.marginRight = "5px"; button.style.cursor = "pointer"; - button.textContent = buttonInfo.name; + button.innerHTML = xmlEscape(buttonInfo.name).replace(/\n/g, "
"); button.style.display = "inline-block"; button.addEventListener("click", () => { this.lastPressBtn = buttonInfo.name; @@ -1455,7 +1467,7 @@ dropdown.className = "dropdown"; const dropdownButton = document.createElement("button"); dropdownButton.className = "dropbtn"; - dropdownButton.textContent = this.DropdownText; + dropdownButton.innerHTML = xmlEscape(this.DropdownText).replace(/\n/g, "
"); const dropdownContent = document.createElement("div"); dropdownContent.id = "myDropdown"; dropdownContent.className = "dropdown-content"; From 723d4af4887743141da7e5a6d188377c6fa1bc29 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 28 Apr 2024 22:14:23 -0700 Subject: [PATCH 37/46] Update Better-Input.js --- extensions/SharkPool/Better-Input.js | 1014 ++++++++------------------ 1 file changed, 300 insertions(+), 714 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index c0f8d9dd91..6676a2553c 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -1,41 +1,36 @@ // Name: Better Input // ID: BetterInputSP -// Description: Expansion of the "ask and wait" Blocks. +// Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// License: LGPL-3.0 -// Version V.4.0.2 +// Version V.4.1.0 (function (Scratch) { "use strict"; - if (!Scratch.extensions.unsandboxed) - throw new Error("Better Input must run unsandboxed"); + if (!Scratch.extensions.unsandboxed) throw new Error("Better Input must run unsandboxed"); const menuIconURI = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; const blockIconURI = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; const formatIcon = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; const colorIcon = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; const effectIcon = - "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; + let newColorType = ""; let overlayImageContainer = ""; const vm = Scratch.vm; const fontMenu = [ - "Sans Serif", - "Serif", - "Handwriting", - "Marker", - "Curly", - "Pixel", - ]; + "Scratch", "Sans Serif", "Serif", + "Handwriting", "Marker", "Curly", "Pixel" + ]; const xmlEscape = function (unsafe) { return Scratch.Cast.toString(unsafe).replace(/[<>&'"]/g, c => { @@ -51,17 +46,11 @@ class BetterInputSP { constructor() { - this.activeOverlays = []; - this.activeUI = []; - this.askBoxPromises = []; - this.isWaitingForInput = false; - this.isDropdownOpen = false; - this.userInput = " "; - this.defaultValue = ""; - this.textBoxX = 0; - this.textBoxY = 0; - this.askBoxInfo = [0, 1]; - this.appendTarget = ["window", false]; + this.activeOverlays = []; this.activeUI = []; this.askBoxPromises = []; + this.isWaitingForInput = false; this.isDropdownOpen = false; + this.userInput = " "; this.defaultValue = ""; + this.textBoxX = 0; this.textBoxY = 0; + this.askBoxInfo = [0, 1]; this.appendTarget = ["window", false]; this.forceInput = "Disabled"; this.overlayInput = null; this.uiOrder = ["question", "input", "buttons"]; @@ -76,8 +65,10 @@ this.fontSize = "14px"; this.textAlign = "left"; this.fontFamily = "Sans Serif"; + // overlay + Image, input, dropdown button this.mainUIinfo = { // Border Radius + dimensions: ["auto", "auto"], overlayRad: 5, inputRad: 4, dropBtnRad: 5, @@ -100,29 +91,17 @@ }; this.lastPressBtn = ""; this.buttonJSON = { - Submit: { - color: "#0074D9", - textColor: "#ffffff", - name: "Submit", - image: "", - imgScale: 100, - borderRadius: 5, - border: "1px none #000000", - padding: "5px 10px", - dropShadow: "none", - outline: ["", 0], + "Submit": { + color: "#0074D9", textColor: "#ffffff", + name: "Submit", image: "", imgScale: 100, + borderRadius: 5, border: "1px none #000000", + padding: "5px 10px", dropShadow: "none", outline: ["", 0] }, - Cancel: { - color: "#d9534f", - textColor: "#ffffff", - name: "Cancel", - image: "", - imgScale: 100, - borderRadius: 5, - border: "1px none #000000", - padding: "5px 10px", - dropShadow: "none", - outline: ["", 0], + "Cancel": { + color: "#d9534f", textColor: "#ffffff", + name: "Cancel", image: "", imgScale: 100, + borderRadius: 5, border: "1px none #000000", + padding: "5px 10px", dropShadow: "none", outline: ["", 0] }, }; @@ -133,18 +112,10 @@ this.dropdownButtonColor = ["#5f5f5f", "#ffffff"]; this.overlayImage = [" ", " ", " "]; - this.Blur = 0; - this.Brightness = 0; - this.Opacity = 100; - this.Invert = 0; - this.Saturation = 100; - this.Hue = 0; - this.Sepia = 0; - this.Contrast = 100; - this.Scale = 100; - this.SkewX = 0; - this.SkewY = 0; - this.Rotation = 90; + this.Blur = 0; this.Brightness = 0; this.Opacity = 100; + this.Invert = 0; this.Saturation = 100; this.Hue = 0; + this.Sepia = 0; this.Contrast = 100; this.Scale = 100; + this.SkewX = 0; this.SkewY = 0; this.Rotation = 90; this.imgScale = [100, 100, 100]; this.shadowS = [0, 0, 5, "#000000"]; } @@ -164,10 +135,7 @@ blockType: Scratch.BlockType.COMMAND, text: "ask [question] and wait", arguments: { - question: { - type: Scratch.ArgumentType.STRING, - defaultValue: "What is your name?", - }, + question: { type: Scratch.ArgumentType.STRING, defaultValue: "What is your name?" } }, }, { @@ -175,61 +143,41 @@ blockType: Scratch.BlockType.REPORTER, text: "ask [question] and wait", arguments: { - question: { - type: Scratch.ArgumentType.STRING, - defaultValue: "What is your name?", - }, + question: { type: Scratch.ArgumentType.STRING, defaultValue: "What is your name?" } }, }, { - opcode: "getUserInput", - blockType: Scratch.BlockType.REPORTER, - text: "user input", + opcode: "getUserInput", blockType: Scratch.BlockType.REPORTER, + text: "user input" }, { opcode: "setDefaultV", blockType: Scratch.BlockType.COMMAND, text: "set default value to [defaultV]", arguments: { - defaultV: { - type: Scratch.ArgumentType.STRING, - defaultValue: "My Name Is...", - }, + defaultV: { type: Scratch.ArgumentType.STRING, defaultValue: "My Name Is..." } }, }, { - opcode: "removeAskBoxes", - blockType: Scratch.BlockType.COMMAND, - text: "remove all ask boxes", + opcode: "removeAskBoxes", blockType: Scratch.BlockType.COMMAND, + text: "remove all ask boxes" }, { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, { - opcode: "setEnable", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: true, - text: "set [ENABLE_MENU] to be [ACTION]", + opcode: "setEnable", blockType: Scratch.BlockType.COMMAND, + hideFromPalette: true, text: "set [ENABLE_MENU] to be [ACTION]", arguments: { - ENABLE_MENU: { - type: Scratch.ArgumentType.STRING, - menu: "enableMenu", - }, - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: "inputActionMenu", - }, + ENABLE_MENU: { type: Scratch.ArgumentType.STRING, menu: "enableMenu" }, + ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } }, }, { - opcode: "getBoxCount", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, - text: "box count", + opcode: "getBoxCount", blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, text: "box count" }, { - opcode: "getMaxCount", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, - text: "box limit", + opcode: "getMaxCount", blockType: Scratch.BlockType.REPORTER, + hideFromPalette: true, text: "box limit" }, { opcode: "setFontSize", @@ -237,7 +185,7 @@ text: "set font size to [SIZE]", blockIconURI: formatIcon, arguments: { - SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 14 }, + SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 14 } }, }, { @@ -246,10 +194,7 @@ text: "set alignment to [ALIGNMENT]", blockIconURI: formatIcon, arguments: { - ALIGNMENT: { - type: Scratch.ArgumentType.STRING, - menu: "alignmentMenu", - }, + ALIGNMENT: { type: Scratch.ArgumentType.STRING, menu: "alignmentMenu" } }, }, { @@ -258,7 +203,7 @@ text: "set font to [FONT]", blockIconURI: formatIcon, arguments: { - FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu" }, + FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu" } }, }, { @@ -270,10 +215,7 @@ x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 2 }, - COLOR: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#ff0000", - }, + COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" } }, }, { @@ -282,11 +224,8 @@ text: "set [ELEMENT] outline to [COLOR] thickness [THICK]", arguments: { ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, - COLOR: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#ff0000", - }, - THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" }, + THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, "---", @@ -296,10 +235,7 @@ text: "set Input Box to be [ACTION]", blockIconURI: formatIcon, arguments: { - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: "inputActionMenu", - }, + ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } }, }, { @@ -308,10 +244,7 @@ text: "set dropdown options to array: [DROPDOWN]", blockIconURI: formatIcon, arguments: { - DROPDOWN: { - type: Scratch.ArgumentType.STRING, - defaultValue: '["Option 1", "Option 2", "Option 3"]', - }, + DROPDOWN: { type: Scratch.ArgumentType.STRING, defaultValue: "[\"Option 1\", \"Option 2\", \"Option 3\"]" } }, }, { @@ -322,7 +255,7 @@ arguments: { MIN: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, - DEFAULT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 }, + DEFAULT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 50 } }, }, { blockType: Scratch.BlockType.LABEL, text: "Buttons" }, @@ -333,17 +266,12 @@ blockIconURI: formatIcon, arguments: { BUTTON: { type: Scratch.ArgumentType.STRING, menu: "buttonType" }, - NAME: { - type: Scratch.ArgumentType.STRING, - defaultValue: "Submit", - }, + NAME: { type: Scratch.ArgumentType.STRING, defaultValue: "Submit" } }, }, { - opcode: "deleteAllButtons", - blockType: Scratch.BlockType.COMMAND, - text: "remove all buttons", - blockIconURI: formatIcon, + opcode: "deleteAllButtons", blockType: Scratch.BlockType.COMMAND, + text: "remove all buttons", blockIconURI: formatIcon }, { opcode: "setButtonText", @@ -351,21 +279,13 @@ text: "set [BUTTON_MENU] button name to [TEXT]", blockIconURI: formatIcon, arguments: { - BUTTON_MENU: { - type: Scratch.ArgumentType.STRING, - menu: "buttonMenu", - }, - TEXT: { - type: Scratch.ArgumentType.STRING, - defaultValue: "my dropdown", - }, + BUTTON_MENU: { type: Scratch.ArgumentType.STRING, menu: "buttonMenu" }, + TEXT: { type: Scratch.ArgumentType.STRING, defaultValue: "my dropdown" } }, }, { - opcode: "lastButton", - blockType: Scratch.BlockType.REPORTER, - text: "last pressed button", - blockIconURI: formatIcon, + opcode: "lastButton", blockType: Scratch.BlockType.REPORTER, + text: "last pressed button", blockIconURI: formatIcon }, { blockType: Scratch.BlockType.LABEL, text: "Positioning" }, { @@ -375,7 +295,7 @@ blockIconURI: formatIcon, arguments: { X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }, }, { @@ -385,7 +305,7 @@ blockIconURI: formatIcon, arguments: { X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }, }, { @@ -395,20 +315,16 @@ blockIconURI: formatIcon, arguments: { X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 } }, }, { - opcode: "getXpos", - blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, - text: "x position", + opcode: "getXpos", blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, text: "x position" }, { - opcode: "getYpos", - blockType: Scratch.BlockType.REPORTER, - blockIconURI: formatIcon, - text: "y position", + opcode: "getYpos", blockType: Scratch.BlockType.REPORTER, + blockIconURI: formatIcon, text: "y position" }, { opcode: "setDirection", @@ -416,7 +332,7 @@ text: "set direction to [ROTATE]", blockIconURI: formatIcon, arguments: { - ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 90 }, + ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 90 } }, }, { @@ -425,14 +341,12 @@ text: "change direction by [ROTATE]", blockIconURI: formatIcon, arguments: { - ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 15 }, + ROTATE: { type: Scratch.ArgumentType.ANGLE, defaultValue: 15 } }, }, { - opcode: "reportDirection", - blockType: Scratch.BlockType.REPORTER, - text: "direction", - blockIconURI: formatIcon, + opcode: "reportDirection", blockType: Scratch.BlockType.REPORTER, + text: "direction", blockIconURI: formatIcon }, { blockType: Scratch.BlockType.LABEL, text: "Visual Settings" }, { @@ -441,45 +355,28 @@ text: "set [COLOR_TYPE] color to [COLOR]", blockIconURI: colorIcon, arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "colorSettingsMenu", - }, - COLOR: { - type: Scratch.ArgumentType.COLOR, - defaultValue: "#000000", - }, + COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "colorSettingsMenu" }, + COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#000000" } }, }, { - opcode: "setGradient", - blockType: Scratch.BlockType.COMMAND, + opcode: "setGradient", blockType: Scratch.BlockType.COMMAND, text: "set [COLOR_TYPE] color to gradient with [COLOR1] and [COLOR2] with direction [DIR]", hideFromPalette: true, //deprecated but needed for support arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - COLOR1: { type: Scratch.ArgumentType.COLOR }, - COLOR2: { type: Scratch.ArgumentType.COLOR }, - DIR: { type: Scratch.ArgumentType.ANGLE }, + COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, + DIR: { type: Scratch.ArgumentType.ANGLE } }, }, { - opcode: "setCircleGradient", - blockType: Scratch.BlockType.COMMAND, + opcode: "setCircleGradient", blockType: Scratch.BlockType.COMMAND, text: "set [COLOR_TYPE] color to radial gradient with [COLOR1] and [COLOR2] at x [X] y [Y]", hideFromPalette: true, //deprecated but needed for support arguments: { - COLOR_TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - COLOR1: { type: Scratch.ArgumentType.COLOR }, - COLOR2: { type: Scratch.ArgumentType.COLOR }, - X: { type: Scratch.ArgumentType.NUMBER }, - Y: { type: Scratch.ArgumentType.NUMBER }, + COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, + X: { type: Scratch.ArgumentType.NUMBER }, Y: { type: Scratch.ArgumentType.NUMBER } }, }, "---", @@ -489,14 +386,8 @@ text: "set [ELEMENT] image to [IMAGE]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - IMAGE: { - type: Scratch.ArgumentType.STRING, - defaultValue: "input-url-here", - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + IMAGE: { type: Scratch.ArgumentType.STRING, defaultValue: "input-url-here" } }, }, { @@ -505,11 +396,8 @@ text: "scale [ELEMENT] image to [SCALE]%", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, - SCALE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, + SCALE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 } }, }, "---", @@ -519,10 +407,7 @@ text: "set box shadow to be [ACTION]", blockIconURI: colorIcon, arguments: { - ACTION: { - type: Scratch.ArgumentType.STRING, - menu: "buttonActionMenu", - }, + ACTION: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } }, }, { @@ -531,11 +416,8 @@ text: "set box shadow [SHADOW] to [AMT]", blockIconURI: colorIcon, arguments: { - SHADOW: { - type: Scratch.ArgumentType.STRING, - menu: "shadowStuff", - }, - AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + SHADOW: { type: Scratch.ArgumentType.STRING, menu: "shadowStuff" }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, "---", @@ -545,10 +427,7 @@ text: "set [ELEMENT] border to [TYPE] color [COLOR] width [WIDTH]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, TYPE: { type: Scratch.ArgumentType.STRING, menu: "borderTypes" }, COLOR: { type: Scratch.ArgumentType.COLOR }, WIDTH: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, @@ -560,10 +439,7 @@ text: "set [ELEMENT] border radius to [VALUE]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, VALUE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, }, }, @@ -573,14 +449,21 @@ text: "set [ELEMENT] padding to T: [N1] B: [N3] L: [N4] R: [N2]", blockIconURI: colorIcon, arguments: { - ELEMENT: { - type: Scratch.ArgumentType.STRING, - menu: "elementMenu", - }, + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, N1: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, N2: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, N3: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, - N4: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + N4: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } + }, + }, + { + opcode: "setDimension", + blockType: Scratch.BlockType.COMMAND, + text: "set Textbox width [W] height [H]", + blockIconURI: colorIcon, + arguments: { + W: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 }, + H: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100 } }, }, { blockType: Scratch.BlockType.LABEL, text: "Effects" }, @@ -588,7 +471,7 @@ opcode: "resetEffect", blockType: Scratch.BlockType.COMMAND, text: "reset effects", - blockIconURI: effectIcon, + blockIconURI: effectIcon }, { opcode: "setEffect", @@ -607,7 +490,7 @@ blockIconURI: effectIcon, arguments: { EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, - AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, { @@ -616,7 +499,7 @@ text: "effect [EFFECT]", blockIconURI: effectIcon, arguments: { - EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" }, + EFFECT: { type: Scratch.ArgumentType.STRING, menu: "effectMenu" } }, }, "---", @@ -626,14 +509,14 @@ text: "when submitted delete textbox after [TIME] secs", blockIconURI: effectIcon, arguments: { - TIME: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, + TIME: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, { opcode: "reportTimeout", blockType: Scratch.BlockType.REPORTER, text: "current textbox timeout", - blockIconURI: effectIcon, + blockIconURI: effectIcon }, { blockType: Scratch.BlockType.LABEL, text: "Operations" }, { @@ -641,16 +524,13 @@ blockType: Scratch.BlockType.COMMAND, text: "set UI order to [ARRAY]", arguments: { - ARRAY: { - type: Scratch.ArgumentType.STRING, - defaultValue: '["question", "input", "buttons"]', - }, + ARRAY: { type: Scratch.ArgumentType.STRING, defaultValue: "[\"question\", \"input\", \"buttons\"]" } }, }, { opcode: "getUIOrder", blockType: Scratch.BlockType.REPORTER, - text: "UI order", + text: "UI order" }, "---", { @@ -658,7 +538,7 @@ blockType: Scratch.BlockType.COMMAND, text: "append next textbox to [TARGET]", arguments: { - TARGET: { type: Scratch.ArgumentType.STRING, menu: "appendMenu" }, + TARGET: { type: Scratch.ArgumentType.STRING, menu: "appendMenu" } }, }, { @@ -666,29 +546,26 @@ blockType: Scratch.BlockType.COMMAND, text: "toggle focus mode to [TYPE]", arguments: { - TYPE: { - type: Scratch.ArgumentType.STRING, - menu: "buttonActionMenu", - }, + TYPE: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } }, }, "---", { opcode: "isWaitingInput", blockType: Scratch.BlockType.BOOLEAN, - text: "is waiting?", + text: "is waiting?" }, { opcode: "isDropdown", blockType: Scratch.BlockType.BOOLEAN, - text: "is dropdown open?", + text: "is dropdown open?" }, { opcode: "setSubmitEvent", blockType: Scratch.BlockType.COMMAND, text: "set force input to [ENTER]", arguments: { - ENTER: { type: Scratch.ArgumentType.STRING, menu: "enterMenu" }, + ENTER: { type: Scratch.ArgumentType.STRING, menu: "enterMenu" } }, }, { @@ -696,7 +573,7 @@ blockType: Scratch.BlockType.COMMAND, text: "set max box count to: [MAX]", arguments: { - MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }, + MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 } }, }, { @@ -704,15 +581,12 @@ blockType: Scratch.BlockType.REPORTER, text: "textbox [INFO]", arguments: { - INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo" }, + INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo" } }, }, ], menus: { - enableMenu: { - acceptReporters: true, - items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"], - }, + enableMenu: { acceptReporters: true, items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"] }, // ^ Old Menu ^ (Needed for V2 Support) fontMenu: { acceptReporters: true, items: "allFonts" }, buttonMenu: { @@ -721,44 +595,24 @@ }, elementMenu: { acceptReporters: true, - items: this.allButtons( - ["Textbox", "Input Box", "Dropdown Button"], - false - ), + items: this.allButtons(["Textbox", "Input Box", "Dropdown Button"], false), }, colorSettingsMenu: { acceptReporters: true, - items: this.allButtons( - [ - "Textbox", - "Question Text", - "Textbox Shadow", - "Input Text", - "Input Box", - "Dropdown Button", - "Dropdown Text", - ], - true - ), + items: this.allButtons([ + "Textbox", "Question Text", "Textbox Shadow", + "Input Text", "Input Box", + "Dropdown Button", "Dropdown Text" + ], true), }, textsMenu: { acceptReporters: true, - items: this.allButtons( - ["Question Text", "Input Text", "Dropdown Text"], - true, - true - ), + items: this.allButtons(["Question Text", "Input Text", "Dropdown Text"], true, true), }, appendMenu: ["window", "canvas"], buttonType: { acceptReporters: true, items: ["add", "remove"] }, - buttonActionMenu: { - acceptReporters: true, - items: ["Enabled", "Disabled"], - }, - alignmentMenu: { - acceptReporters: true, - items: ["left", "right", "center"], - }, + buttonActionMenu: { acceptReporters: true, items: ["Enabled", "Disabled"] }, + alignmentMenu: { acceptReporters: true, items: ["left", "right", "center"] }, shadowStuff: { acceptReporters: true, items: ["Size", "X", "Y"] }, boxInfo: { acceptReporters: true, @@ -767,31 +621,18 @@ inputActionMenu: { acceptReporters: true, items: [ - "None", - "Text", - "Password", - "Number", - "Color", - "Dropdown", - "Multi-Select Dropdown", - "Horizontal Slider", - "Vertical Slider", + "None", "Text", "Password", "Number", "Color", + "Dropdown", "Multi-Select Dropdown", + "Horizontal Slider", "Vertical Slider" ], }, effectMenu: { acceptReporters: true, items: [ - "Blur", - "Brightness", - "Opacity", - "Invert", - "Saturation", - "Hue", - "Sepia", - "Contrast", - "Scale", - "SkewX", - "SkewY", + "Blur", "Brightness", "Opacity", + "Invert", "Saturation", "Hue", + "Sepia", "Contrast", + "Scale", "SkewX", "SkewY", ], }, enterMenu: { @@ -801,17 +642,10 @@ borderTypes: { acceptReporters: true, items: [ - "none", - "solid", - "dotted", - "dashed", - "double", - "groove", - "ridge", - "inset", - "outset", + "none", "solid", "dotted", "dashed", + "double", "groove", "ridge", "inset", "outset" ], - }, + } }, }; } @@ -819,21 +653,17 @@ allFonts() { const customFonts = Scratch.vm.runtime.fontManager ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({ - text: i.name, - value: i.family, + text: i.name, value: i.family })) : []; - return [...fontMenu, ...customFonts]; + return [ ...fontMenu, ...customFonts ]; } allButtons(array, enableTxt, justTxt) { let customBtn = Object.keys(this.buttonJSON); - if (justTxt) customBtn = customBtn.map((btn) => btn + " Text"); - else if (enableTxt) - customBtn.forEach((btn) => { - customBtn.push(btn + " Text"); - }); - return [...array, ...customBtn]; + if (justTxt) customBtn = customBtn.map(btn => btn + " Text"); + else if (enableTxt) customBtn.forEach((btn) => { customBtn.push(btn + " Text") }); + return [ ...array, ...customBtn ]; } updateOverlayPos(overlay) { @@ -845,7 +675,7 @@ overlay.style.top = `${50 + this.textBoxY}%`; } overlay.style.transform = ` - translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)`} + translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)` } SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) `; @@ -855,19 +685,13 @@ } } updateOverlay(overlay) { - const newOpacity = this.Opacity / 100; + const newOpacity = this.Opacity / 100; const newBrightness = this.Brightness + 100; overlay.style.backgroundImage = ""; - overlay.style[ - this.textBoxColor[0].includes("gradient") - ? "backgroundImage" - : "backgroundColor" - ] = this.textBoxColor[0]; - overlay.style.boxShadow = this.shadowEnabled - ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px ${this.shadowS[3]}` - : "none"; + overlay.style[this.textBoxColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.textBoxColor[0]; + overlay.style.boxShadow = this.shadowEnabled ? `${this.shadowS[0]}px ${this.shadowS[1]}px ${this.shadowS[2]}px ${this.shadowS[3]}` : "none"; overlay.style.transform = ` - translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)`} + translate${this.appendTarget[0] === "window" ? "(-50%, -50%)" : `(${-50 + this.textBoxX}%, ${-50 + this.textBoxY}%)` } SkewX(${this.SkewX}deg) SkewY(${this.SkewY}deg) rotate(${this.Rotation - 90}deg) scale(${this.Scale / 100}) `; @@ -883,13 +707,11 @@ overlay.style.fontFamily = this.fontFamily; overlay.style.textAlign = this.textAlign; overlay.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; + overlay.style.width = this.mainUIinfo.dimensions[0]; + overlay.style.height = this.mainUIinfo.dimensions[1]; overlayImageContainer.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; overlayImageContainer.style.background = ""; - this.setImageStyles( - overlayImageContainer, - this.overlayImage[0], - this.imgScale[0] - ); + this.setImageStyles(overlayImageContainer, this.overlayImage[0], this.imgScale[0]); this.updateButtonImages(overlay); } updateButtonImages(overlay) { @@ -901,22 +723,13 @@ } const inputField = overlay.querySelector("input"); if (inputField) { - inputField.style.width = - this.isInputEnabled === "Color" ? "100%" : "auto"; + inputField.style.width = this.isInputEnabled === "Color" ? "100%" : "auto"; inputField.style.background = ""; inputField.style.fontFamily = this.fontFamily; - inputField.style[ - this.inputFieldColor.includes("gradient") - ? "backgroundImage" - : "backgroundColor" - ] = this.inputFieldColor; + inputField.style[this.inputFieldColor.includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.inputFieldColor; inputField.style.color = this.inputColor; inputField.style.textShadow = this.mainUIinfo.inputTxtShad; - this.tryOutline( - inputField, - this.mainUIinfo.inputOutline[0], - this.mainUIinfo.inputOutline[1] - ); + this.tryOutline(inputField, this.mainUIinfo.inputOutline[0], this.mainUIinfo.inputOutline[1]); inputField.style.border = this.mainUIinfo.inputBord; inputField.style.borderRadius = `${this.mainUIinfo.inputRad}px`; inputField.style.padding = this.mainUIinfo.inputPad; @@ -932,16 +745,8 @@ dropBtn.style.border = this.mainUIinfo.dropBtnBord; dropBtn.style.padding = this.mainUIinfo.dropBtnPad; dropBtn.style.textShadow = this.mainUIinfo.dropBtnTxtShad; - this.tryOutline( - dropBtn, - this.mainUIinfo.dropBtnOutline[0], - this.mainUIinfo.dropBtnOutline[1] - ); - dropBtn.style[ - this.dropdownButtonColor[0].includes("gradient") - ? "backgroundImage" - : "backgroundColor" - ] = this.dropdownButtonColor[0]; + this.tryOutline(dropBtn, this.mainUIinfo.dropBtnOutline[0], this.mainUIinfo.dropBtnOutline[1]); + dropBtn.style[this.dropdownButtonColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdownButtonColor[0]; this.setImageStyles(dropBtn, this.overlayImage[2], this.imgScale[2]); } const buttonContainer = overlay.querySelector(".button-container"); @@ -957,17 +762,9 @@ button.style.border = buttonInfo.border; button.style.padding = buttonInfo.padding; button.style.textShadow = buttonInfo.dropShadow; - this.tryOutline( - button, - buttonInfo.outline[0], - buttonInfo.outline[1] - ); + this.tryOutline(button, buttonInfo.outline[0], buttonInfo.outline[1]); button.style.background = ""; - button.style[ - buttonInfo.color.includes("gradient") - ? "backgroundImage" - : "background" - ] = buttonInfo.color; + button.style[buttonInfo.color.includes("gradient") ? "backgroundImage" : "background"] = buttonInfo.color; this.setImageStyles(button, buttonInfo.image, buttonInfo.imgScale); } }); @@ -989,75 +786,44 @@ if (canFetch) { element.style.background = `url(${encodeURI(url)})`; element.style.backgroundSize = `${scale}%`; - } else { - console.log("Cannot fetch content from the URL"); - } + } else { console.log("Cannot fetch content from the URL") } }); } } - showEffect(args) { - return this[args.EFFECT]; - } + showEffect(args) { return this[args.EFFECT] } setEffect(args) { this[args.EFFECT] = args.AMT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } changeEffect(args) { const effect = args.EFFECT; this[effect] = this[effect] + args.AMT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } resetEffect() { - this.Blur = 0; - this.Brightness = 0; - this.Opacity = 100; - this.Invert = 0; - this.Saturation = 100; - this.Hue = 0; - this.Sepia = 0; - this.Contrast = 100; - this.Scale = 100; - this.SkewX = 0; - this.SkewY = 0; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.Blur = 0; this.Brightness = 0; this.Opacity = 100; this.Invert = 0; + this.Saturation = 100; this.Hue = 0; this.Sepia = 0; this.Contrast = 100; + this.Scale = 100; this.SkewX = 0; this.SkewY = 0; + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setColorSettings(args) { const colorType = args.COLOR_TYPE; const colorValue = args.COLOR; const colorTypeMap = { - "Question Text": () => (this.questionColor = colorValue), - "Input Text": () => (this.inputColor = colorValue), - Textbox: () => { - this.textBoxColor[0] = colorValue; - this.overlayImage[0] = " "; - }, - "Textbox Shadow": () => { - this.shadowS[3] = colorValue; - }, - "Input Box": () => { - this.inputFieldColor = colorValue; - this.overlayImage[1] = " "; - }, - "Dropdown Button": () => { - this.dropdownButtonColor[0] = colorValue; - this.overlayImage[2] = " "; - }, - "Dropdown Text": () => (this.dropdownButtonColor[1] = colorValue), + "Question Text": () => this.questionColor = colorValue, + "Input Text": () => this.inputColor = colorValue, + "Textbox": () => { this.textBoxColor[0] = colorValue; this.overlayImage[0] = " "; }, + "Textbox Shadow": () => { this.shadowS[3] = colorValue }, + "Input Box": () => { this.inputFieldColor = colorValue; this.overlayImage[1] = " "; }, + "Dropdown Button": () => { this.dropdownButtonColor[0] = colorValue; this.overlayImage[2] = " "; }, + "Dropdown Text": () => this.dropdownButtonColor[1] = colorValue, }; - const buttonInfo = - this.buttonJSON[colorType] || - this.buttonJSON[colorType.replace(" Text", "")]; + const buttonInfo = this.buttonJSON[colorType] || this.buttonJSON[colorType.replace(" Text", "")]; if (buttonInfo) { if (colorType.includes(" Text")) { buttonInfo.textColor = colorValue; @@ -1068,34 +834,29 @@ } const applyColor = colorTypeMap[colorType]; if (applyColor) applyColor(); - this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } findGradientType(menu) { const colorTypeMap = { Textbox: { newColorType: "textBoxColor", ind: 0 }, - "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 }, + "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 } }; if (colorTypeMap[menu]) { const { newColorType, ind } = colorTypeMap[menu]; this.overlayImage[ind] = " "; return newColorType; - } else if (this.buttonJSON[menu]) { - return ["button", menu]; - } + } else if (this.buttonJSON[menu]) { return ["button", menu] } return menu; } setGradient(args) { - if (args.COLOR_TYPE === "Input Box") - throw new Error("As of Better Input V4, this Option no Longer Works"); + if (args.COLOR_TYPE === "Input Box") throw new Error ("As of Better Input V4, this Option no Longer Works"); const newColorType = this.findGradientType(args.COLOR_TYPE); const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; else this.buttonJSON[newColorType[1]].color = gradientColor; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setCircleGradient(args) { const newColorType = this.findGradientType(args.COLOR_TYPE); @@ -1103,9 +864,7 @@ const gradientColor = `radial-gradient(circle at ${newPos[0]}% ${newPos[1]}%, ${args.COLOR2}, ${args.COLOR1})`; if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; else this.buttonJSON[newColorType[1]].color = gradientColor; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } callStyling(element, value, type, elements) { @@ -1118,64 +877,48 @@ setBorder(args) { const width = Scratch.Cast.toNumber(args.WIDTH); const string = `${width}px ${args.TYPE} ${args.COLOR}`; - this.callStyling(args.ELEMENT, string, "border", { - Textbox: "overlayBord", - "Input Box": "inputBord", - "Dropdown Button": "dropBtnBord" - }); + this.callStyling( + args.ELEMENT, string, "border", + { Textbox: "overlayBord", "Input Box": "inputBord", "Dropdown Button": "dropBtnBord" } + ); } setBorderRadius(args) { - this.callStyling(args.ELEMENT, Math.max(args.VALUE, 0), "borderRadius", { - Textbox: "overlayRad", - "Input Box": "inputRad", - "Dropdown Button": "dropBtnRad" - }); + this.callStyling( + args.ELEMENT, Math.max(args.VALUE, 0), "borderRadius", + { Textbox: "overlayRad", "Input Box": "inputRad", "Dropdown Button": "dropBtnRad" } + ); } setPadding(args) { const casted = [ - Scratch.Cast.toNumber(args.N1), - Scratch.Cast.toNumber(args.N2), - Scratch.Cast.toNumber(args.N3), - Scratch.Cast.toNumber(args.N4), + Scratch.Cast.toNumber(args.N1), Scratch.Cast.toNumber(args.N2), + Scratch.Cast.toNumber(args.N3), Scratch.Cast.toNumber(args.N4) ]; let pad = `${casted[0]}px ${casted[1]}px ${casted[2]}px ${casted[3]}px`; - this.callStyling(args.ELEMENT, pad, "padding", { - Textbox: "overlayPad", - "Input Box": "inputPad", - "Dropdown Button": "dropBtnPad" - }); + this.callStyling( + args.ELEMENT, pad, "padding", + { Textbox: "overlayPad", "Input Box": "inputPad", "Dropdown Button": "dropBtnPad" } + ); } setDropShadow(args) { const casted = [ - Scratch.Cast.toNumber(args.x), - Scratch.Cast.toNumber(args.y), + Scratch.Cast.toNumber(args.x), Scratch.Cast.toNumber(args.y), Scratch.Cast.toNumber(args.z), ]; - let shadow = - args.z === 0 - ? "none" - : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; - this.callStyling(args.ELEMENT.slice(0, -5), shadow, "dropShadow", { - "Question": "overlayTxtShad", - "Input": "inputTxtShad", - "Dropdown": "dropBtnTxtShad" - }); + let shadow = args.z === 0 ? "none" : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; + this.callStyling( + args.ELEMENT.slice(0, -5), shadow, "dropShadow", + { "Question": "overlayTxtShad", "Input": "inputTxtShad", "Dropdown": "dropBtnTxtShad" } + ); } setOutline(args) { const thick = Scratch.Cast.toNumber(args.THICK); this.callStyling( - args.ELEMENT.slice(0, -5), - [args.COLOR, thick], - "outline", - { - "Question": "overlayOutline", - "Input": "inputOutline", - "Dropdown": "dropBtnOutline" - } + args.ELEMENT.slice(0, -5), [args.COLOR, thick], "outline", + { "Question": "overlayOutline", "Input": "inputOutline", "Dropdown": "dropBtnOutline" } ); } @@ -1183,45 +926,44 @@ const shadowMap = { Size: 2, X: 0, Y: 1 }; const propertyIndex = shadowMap[args.SHADOW]; if (propertyIndex !== undefined) this.shadowS[propertyIndex] = args.AMT; - this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setImage(args) { const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; const elementIndex = elementMap[args.ELEMENT]; - if (elementIndex !== undefined) - this.overlayImage[elementIndex] = args.IMAGE; - else if (this.buttonJSON[args.ELEMENT]) - this.buttonJSON[args.ELEMENT].image = args.IMAGE; - this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + if (elementIndex !== undefined) this.overlayImage[elementIndex] = args.IMAGE; + else if (this.buttonJSON[args.ELEMENT]) this.buttonJSON[args.ELEMENT].image = args.IMAGE; + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } scaleImage(args) { const elementMap = { Textbox: 0, "Input Box": 1, "Dropdown Button": 2 }; const elementIndex = elementMap[args.ELEMENT]; if (elementIndex !== undefined) this.imgScale[elementIndex] = args.SCALE; - else if (this.buttonJSON[args.ELEMENT]) - this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; - this.activeOverlays.forEach((overlay) => this.updateOverlay(overlay)); + else if (this.buttonJSON[args.ELEMENT]) this.buttonJSON[args.ELEMENT].imgScale = args.SCALE; + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); + } + + setDimension(args) { + const w = `${Scratch.Cast.toNumber(args.W)}px`; + const h = `${Scratch.Cast.toNumber(args.H)}px`; + // Negative numbers result in auto-dimensions + this.mainUIinfo.dimensions = [w.includes("-") ? "auto" : w, h.includes("-") ? "auto" : h]; + this.activeOverlays.forEach(overlay => this.updateOverlay(overlay)); } setDirection(args) { this.Rotation = Scratch.Cast.toNumber(args.ROTATE); - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } changeDirection(args) { this.Rotation = this.Rotation + Scratch.Cast.toNumber(args.ROTATE); - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } - reportDirection() { - return this.Rotation; - } + reportDirection() { return this.Rotation } setPrePosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); @@ -1231,61 +973,39 @@ setPosition(args) { this.textBoxX = Scratch.Cast.toNumber(args.X) / (screen.width / 400); this.textBoxY = Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - this.activeOverlays.forEach((overlay) => { - this.updateOverlayPos(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay) }); } changePosition(args) { - this.textBoxX = - this.textBoxX + Scratch.Cast.toNumber(args.X) / (screen.width / 400); - this.textBoxY = - this.textBoxY + Scratch.Cast.toNumber(args.Y) / (screen.height / -300); - this.activeOverlays.forEach((overlay) => { - this.updateOverlayPos(overlay); - }); + this.textBoxX = this.textBoxX + Scratch.Cast.toNumber(args.X) / (screen.width / 400); + this.textBoxY = this.textBoxY + Scratch.Cast.toNumber(args.Y) / (screen.height / -300); + this.activeOverlays.forEach((overlay) => { this.updateOverlayPos(overlay) }); } - getXpos() { - return this.textBoxX * (screen.width / 400); - } - getYpos() { - return this.textBoxY * (screen.height / -300); - } + getXpos() { return this.textBoxX * (screen.width / 400) } + getYpos() { return this.textBoxY * (screen.height / -300) } - setFontSize(args) { - this.fontSize = args.SIZE + "px"; - } + setFontSize(args) { this.fontSize = args.SIZE + "px" } setTextAlignment(args) { this.textAlign = args.ALIGNMENT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } setFontFamily(args) { this.fontFamily = args.FONT; - this.activeOverlays.forEach((overlay) => { - this.updateOverlay(overlay); - }); + this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); } - setSlider(args) { - this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT]; - } + setSlider(args) { this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT] } setInputType(args) { - if (args.ACTION === "Text" || args.ACTION === "None") { + if (args.ACTION === "Text" || args.ACTION === "None") { this.isInputEnabled = args.ACTION === "Text" ? "Enabled" : "Disabled"; - } else { - this.isInputEnabled = args.ACTION; - } + } else { this.isInputEnabled = args.ACTION } } - enableShadow(args) { - this.shadowEnabled = args.ACTION === "Enabled"; - } + enableShadow(args) { this.shadowEnabled = args.ACTION === "Enabled" } setButtonText(args) { const buttonMenu = args.BUTTON_MENU; @@ -1301,9 +1021,7 @@ setDropdown(args) { try { this.optionList = JSON.parse(args.DROPDOWN); - } catch { - this.optionList = ["Undefined Array Error"]; - } + } catch { this.optionList = ["Undefined Array Error"] } } removeAskBoxes() { @@ -1312,9 +1030,7 @@ if (overlay) { if (this.appendTarget[0] === "window" && overlay.parentNode) { overlay.parentNode.removeChild(overlay); - } else if ( - overlay.parentNode.parentNode !== document.documentElement - ) { + } else if (overlay.parentNode.parentNode !== document.documentElement) { overlay.parentNode.parentNode.removeChild(overlay.parentNode); } overlaysToRemove.push(overlay); @@ -1325,23 +1041,17 @@ } }); this.askBoxPromises = []; - this.activeOverlays = this.activeOverlays.filter( - (overlay) => !overlaysToRemove.includes(overlay) - ); + this.activeOverlays = this.activeOverlays.filter((overlay) => !overlaysToRemove.includes(overlay)); this.activeUI = []; this.askBoxInfo[0] = 0; // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info const bugged = document.querySelectorAll(`[class^="SP-ask-box"]`); - bugged.forEach((box) => { - box.parentNode.removeChild(box); - }); + bugged.forEach((box) => { box.parentNode.removeChild(box) }); } askAndWaitForInput(args) { - if (this.askBoxInfo[0] < this.askBoxInfo[1]) { - return this.askAndWait(args).then(() => { - return this.getUserInput(); - }); + if (this.askBoxInfo[0] < this.askBoxInfo[1] ) { + return this.askAndWait(args).then(() => { return this.getUserInput() }); } } @@ -1361,18 +1071,14 @@ overlay.style.position = "fixed"; overlay.style.zIndex = "9999"; overlay.style.fontSize = this.fontSize; - overlay.style.left = - this.appendTarget[0] === "window" ? `${50 + this.textBoxX}%` : "0%"; - overlay.style.top = - this.appendTarget[0] === "window" ? `${50 + this.textBoxY}%` : "0%"; + overlay.style.left = this.appendTarget[0] === "window" ? `${50 + this.textBoxX}%` : "0%"; + overlay.style.top = this.appendTarget[0] === "window" ? `${50 + this.textBoxY}%` : "0%"; const focusBG = document.createElement("div"); - focusBG.style.cssText = - "pointer-events: auto; position: fixed; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 9998;"; + focusBG.style.cssText = "pointer-events: auto; position: fixed; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 9998;"; focusBG.className = "SP-ask-boxBG"; focusBG.id = this.appendTarget[0]; - focusBG.style.left = - this.appendTarget[0] === "window" ? "0%" : "-50%"; + focusBG.style.left = this.appendTarget[0] === "window" ? "0%" : "-50%"; focusBG.style.top = this.appendTarget[0] === "window" ? "0%" : "-50%"; overlayImageContainer = document.createElement("div"); @@ -1383,19 +1089,9 @@ overlayImageContainer.style.left = 0; overlayImageContainer.style.zIndex = "-1"; if (this.forceInput !== "Disabled") { - const overlayInput = - this.forceInput === "Enter Key" - ? "Enter" - : this.forceInput === "Shift + Enter Key" - ? "ShiftEnter" - : this.forceInput; + const overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; const handleKeydown = (event) => { - if ( - (overlayInput === "ShiftEnter" && - event.shiftKey && - event.key === "Enter") || - event.key === overlayInput - ) { + if ((overlayInput === "ShiftEnter" && event.shiftKey && event.key === "Enter") || event.key === overlayInput) { this.userInput = inputField.value; this.closeOverlay(overlay); resolve(); @@ -1403,10 +1099,7 @@ }; const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { - if ( - mutation.type === "childList" && - !document.contains(overlay) - ) { + if (mutation.type === "childList" && !document.contains(overlay)) { document.removeEventListener("keydown", handleKeydown); observer.disconnect(); } @@ -1419,10 +1112,8 @@ const questionText = document.createElement("div"); questionText.classList.add("question"); questionText.style.fontSize = this.fontSize; - if (this.uiOrder[0] !== "question") - questionText.style.marginTop = "10px"; - if (this.uiOrder[0] === "question") - questionText.style.marginBottom = "10px"; + if (this.uiOrder[0] !== "question") questionText.style.marginTop = "10px"; + if (this.uiOrder[0] === "question") questionText.style.marginBottom = "10px"; questionText.innerHTML = xmlEscape(question).replace(/\n/g, "
"); const inputField = document.createElement("input"); @@ -1430,9 +1121,7 @@ inputField.style.fontSize = this.fontSize; inputField.style.margin = "0 auto"; inputField.type = this.isInputEnabled.toLowerCase(); - inputField.addEventListener("input", () => { - this.userInput = inputField.value; - }); + inputField.addEventListener("input", () => { this.userInput = inputField.value }); const buttonContainer = document.createElement("div"); buttonContainer.classList.add("button-container"); for (const buttonName in this.buttonJSON) { @@ -1442,20 +1131,15 @@ buttonContainer.appendChild(lineBreak); } else { const button = document.createElement("button"); - if (this.uiOrder[0] !== "buttons") - button.style.marginTop = "10px"; - if (this.uiOrder[2] !== "buttons") - button.style.marginBottom = "10px"; + if (this.uiOrder[0] !== "buttons") button.style.marginTop = "10px"; + if (this.uiOrder[2] !== "buttons") button.style.marginBottom = "10px"; button.style.marginRight = "5px"; button.style.cursor = "pointer"; button.innerHTML = xmlEscape(buttonInfo.name).replace(/\n/g, "
"); button.style.display = "inline-block"; button.addEventListener("click", () => { this.lastPressBtn = buttonInfo.name; - this.userInput = - this.isInputEnabled === "Disabled" - ? buttonInfo.name - : inputField.value; + this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; this.closeOverlay(overlay); resolve(); }); @@ -1479,27 +1163,17 @@ optionLabel.style.color = this.questionColor; optionLabel.textContent = ""; const optionRadio = document.createElement("input"); - optionRadio.type = - this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; + optionRadio.type = this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; optionRadio.name = "dropdownOptions"; optionRadio.value = index; optionRadio.classList.add("dropdown-radio"); optionRadio.addEventListener("click", () => { if (this.isInputEnabled === "Multi-Select Dropdown") { if (selectedOptions.includes(label)) { - selectedOptions = selectedOptions.filter( - (item) => item !== label - ); - } else { - selectedOptions.push(label); - } - inputField.value = - selectedOptions.length > 0 - ? JSON.stringify(selectedOptions) - : ""; - } else { - inputField.value = label; - } + selectedOptions = selectedOptions.filter(item => item !== label); + } else { selectedOptions.push(label) } + inputField.value = selectedOptions.length > 0 ? JSON.stringify(selectedOptions) : ""; + } else { inputField.value = label } this.userInput = inputField.value; }); optionLabel.appendChild(optionRadio); @@ -1510,32 +1184,23 @@ document.body.appendChild(dropdown); dropdownButton.addEventListener("click", () => { this.lastPressBtn = this.DropdownText; - dropdownContent.style.display = this.isDropdownOpen - ? "none" - : "block"; + dropdownContent.style.display = this.isDropdownOpen ? "none" : "block"; this.isDropdownOpen = !this.isDropdownOpen; }); const sliderContainer = document.createElement("div"); sliderContainer.classList.add("slider-container"); const slider = document.createElement("input"); - if (this.isInputEnabled.includes("Vertical")) - slider.style.transform = "rotate(270deg)"; + if (this.isInputEnabled.includes("Vertical")) slider.style.transform = "rotate(270deg)"; slider.type = "range"; slider.min = this.sliderInfo[0]; slider.max = this.sliderInfo[1]; slider.value = this.sliderInfo[2]; if (this.isInputEnabled.includes("Vertical")) { - for (let i = 0; i < 3; i++) { - sliderContainer.appendChild(document.createElement("br")); - } + for (let i = 0; i < 3; i++) { sliderContainer.appendChild(document.createElement("br")) } sliderContainer.appendChild(slider); - for (let i = 0; i < 4; i++) { - sliderContainer.appendChild(document.createElement("br")); - } - } else { - sliderContainer.appendChild(slider); - } + for (let i = 0; i < 4; i++) { sliderContainer.appendChild(document.createElement("br")) } + } else { sliderContainer.appendChild(slider) } const valueDisplay = document.createElement("span"); valueDisplay.classList.add("slider-value"); sliderContainer.appendChild(valueDisplay); @@ -1548,17 +1213,11 @@ }); for (const item of this.uiOrder) { switch (item) { - case "question": { - overlay.appendChild(questionText); - break; - } + case "question": { overlay.appendChild(questionText); break } case "input": if (this.isInputEnabled !== "Disabled") { - if ( - this.isInputEnabled === "Enabled" || - this.isInputEnabled === "Color" || - this.isInputEnabled === "Number" || - this.isInputEnabled === "Password" + if (this.isInputEnabled === "Enabled" || this.isInputEnabled === "Color" || + this.isInputEnabled === "Number" || this.isInputEnabled === "Password" ) { overlay.appendChild(inputField); } else if (this.isInputEnabled.includes("Dropdown")) { @@ -1572,10 +1231,7 @@ } } break; - case "buttons": { - overlay.appendChild(buttonContainer); - break; - } + case "buttons": { overlay.appendChild(buttonContainer); break } } } overlay.appendChild(overlayImageContainer); @@ -1586,13 +1242,7 @@ inputField.focus(); inputField.value = this.defaultValue; this.activeOverlays.push(overlay); - this.activeUI.push({ - overlay: { - button: buttonContainer, - dropdown: dropdownButton, - input: inputField, - }, - }); + this.activeUI.push({ overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField } }); if (this.appendTarget[0] === "window") { const resizeHandler = () => { overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; @@ -1604,26 +1254,11 @@ document.addEventListener("MSFullscreenChange", resizeHandler); const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { - if ( - mutation.type === "childList" && - Array.from(mutation.removedNodes).includes(overlay) - ) { - document.removeEventListener( - "fullscreenchange", - resizeHandler - ); - document.removeEventListener( - "webkitfullscreenchange", - resizeHandler - ); - document.removeEventListener( - "mozfullscreenchange", - resizeHandler - ); - document.removeEventListener( - "MSFullscreenChange", - resizeHandler - ); + if (mutation.type === "childList" && Array.from(mutation.removedNodes).includes(overlay)) { + document.removeEventListener("fullscreenchange", resizeHandler); + document.removeEventListener("webkitfullscreenchange", resizeHandler); + document.removeEventListener("mozfullscreenchange", resizeHandler); + document.removeEventListener("MSFullscreenChange", resizeHandler); observer.disconnect(); } } @@ -1631,8 +1266,7 @@ observer.observe(overlay.parentNode, { childList: true }); document.body.appendChild(overlay); } else { - if (this.appendTarget[1]) - vm.renderer.addOverlay(focusBG, "scale-centered"); + if (this.appendTarget[1]) vm.renderer.addOverlay(focusBG, "scale-centered"); vm.renderer.addOverlay(overlay, "scale-centered"); } inputField.focus(); @@ -1654,8 +1288,7 @@ this.askBoxPromises.splice(index, 1); } delete this.activeUI[overlay]; - if (this.appendTarget[0] === "window") - document.body.removeChild(overlay); + if (this.appendTarget[0] === "window") document.body.removeChild(overlay); else vm.renderer.removeOverlay(overlay); if (usedBG) { if (usedBG.id === "window") document.body.removeChild(usedBG); @@ -1667,20 +1300,13 @@ setButton(args) { if (args.BUTTON === "add") { this.buttonJSON[args.NAME] = { - borderRadius: 5, - border: "1px none #000000", - color: "#0074D9", - textColor: "#ffffff", - name: args.NAME, - padding: "5px 10px", - image: "", - imgScale: 100, - dropShadow: "none", - outline: ["", 0], + borderRadius: 5, border: "1px none #000000", + color: "#0074D9", textColor: "#ffffff", + name: args.NAME, padding: "5px 10px", + image: "", imgScale: 100, + dropShadow: "none", outline: ["", 0] }; - } else { - delete this.buttonJSON[args.NAME]; - } + } else { delete this.buttonJSON[args.NAME] } Scratch.vm.extensionManager.refreshBlocks(); } @@ -1689,94 +1315,54 @@ Scratch.vm.extensionManager.refreshBlocks(); } - lastButton() { - return this.lastPressBtn; - } + lastButton() { return this.lastPressBtn } - isWaitingInput() { - return this.isWaitingForInput; - } + isWaitingInput() { return this.isWaitingForInput } - isDropdown() { - return this.isDropdownOpen; - } + isDropdown() { return this.isDropdownOpen } - setMaxBoxCount(args) { - this.askBoxInfo[1] = args.MAX; - } + setMaxBoxCount(args) { this.askBoxInfo[1] = args.MAX } setTimeout(args) { this.Timeout = args.TIME; this.Condition = args.CONDITION; } - reportTimeout() { - return this.Timeout; - } + reportTimeout() { return this.Timeout } - getUserInput() { - return this.userInput === null ? "" : this.userInput; - } + getUserInput() { return this.userInput === null ? "" : this.userInput } getBoxInfo(args) { if (args.INFO.includes("button")) { const buttons = Object.keys(this.buttonJSON); - return args.INFO.includes("names") - ? JSON.stringify(buttons) - : buttons.length; - } else { - return this.askBoxInfo[args.INFO === "count" ? 0 : 1]; - } + return args.INFO.includes("names") ? JSON.stringify(buttons) : buttons.length; + } else { return this.askBoxInfo[args.INFO === "count" ? 0 : 1] } } - setSubmitEvent(args) { - this.forceInput = args.ENTER; - } + setSubmitEvent(args) { this.forceInput = args.ENTER } - setDefaultV(args) { - this.defaultValue = args.defaultV; - } + setDefaultV(args) { this.defaultValue = args.defaultV } - setAppend(args) { - this.appendTarget[0] = args.TARGET; - } - setFocus(args) { - this.appendTarget[1] = args.TYPE === "Enabled"; - } + setAppend(args) { this.appendTarget[0] = args.TARGET } + setFocus(args) { this.appendTarget[1] = args.TYPE === "Enabled" } setUI(args) { let array; - try { - array = JSON.parse(args.ARRAY.toLowerCase()); - } catch { - return; - } + try { array = JSON.parse(args.ARRAY.toLowerCase()) } catch { return } if (!Array.isArray(array)) return; const allowedUI = ["question", "input", "buttons"]; - let filteredArray = [ - ...new Set(array.filter((element) => allowedUI.includes(element))), - ]; - allowedUI.forEach((element) => { + let filteredArray = [...new Set(array.filter(element => allowedUI.includes(element)))]; + allowedUI.forEach(element => { if (!filteredArray.includes(element)) filteredArray.push(element); }); this.uiOrder = filteredArray; } - getUIOrder() { - return JSON.stringify(this.uiOrder); - } + getUIOrder() { return JSON.stringify(this.uiOrder) } - setEnable() { - throw new Error( - "This Block has been removed since Better Input V3. Please use the New Powerful Blocks" - ); - } - getBoxCount() { - return this.askBoxInfo[0]; - } //Legacy - getMaxCount() { - return this.askBoxInfo[1]; - } //Legacy + setEnable() { throw new Error("This Block has been removed since Better Input V3. Please use the New Powerful Blocks") } + getBoxCount() { return this.askBoxInfo[0] } //Legacy + getMaxCount() { return this.askBoxInfo[1] } //Legacy } Scratch.extensions.register(new BetterInputSP()); From bf1a359dcc8e863a4dfac1451bca6e8844281a44 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:54:42 -0700 Subject: [PATCH 38/46] quality of life fixes --- extensions/SharkPool/Better-Input.js | 108 +++++++++++++++++++-------- 1 file changed, 75 insertions(+), 33 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 6676a2553c..52da7fad2a 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -3,7 +3,7 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.4.1.0 +// Version V.4.1.1 (function (Scratch) { "use strict"; @@ -162,6 +162,10 @@ opcode: "removeAskBoxes", blockType: Scratch.BlockType.COMMAND, text: "remove all ask boxes" }, + { + opcode: "resetInput", blockType: Scratch.BlockType.COMMAND, + text: "reset user input" + }, { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, { opcode: "setEnable", blockType: Scratch.BlockType.COMMAND, @@ -1049,6 +1053,8 @@ bugged.forEach((box) => { box.parentNode.removeChild(box) }); } + resetInput() { this.userInput = this.askBoxInfo[1] > 1 ? "[]" : "" } + askAndWaitForInput(args) { if (this.askBoxInfo[0] < this.askBoxInfo[1] ) { return this.askAndWait(args).then(() => { return this.getUserInput() }); @@ -1058,6 +1064,8 @@ askAndWait(args) { if (this.askBoxInfo[0] < this.askBoxInfo[1]) { const question = args.question; + let hasDecreased = false; // for the box counter + const index = this.askBoxInfo[0]; this.isWaitingForInput = true; this.lastPressBtn = ""; this.askBoxInfo[0]++; @@ -1092,8 +1100,14 @@ const overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; const handleKeydown = (event) => { if ((overlayInput === "ShiftEnter" && event.shiftKey && event.key === "Enter") || event.key === overlayInput) { - this.userInput = inputField.value; - this.closeOverlay(overlay); + if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; + else { + const newInput = [...this.userInput]; + newInput[index] = inputField.value; + this.userInput = newInput; + } + this.closeOverlay(overlay, hasDecreased); + hasDecreased = true; resolve(); } }; @@ -1121,7 +1135,14 @@ inputField.style.fontSize = this.fontSize; inputField.style.margin = "0 auto"; inputField.type = this.isInputEnabled.toLowerCase(); - inputField.addEventListener("input", () => { this.userInput = inputField.value }); + inputField.addEventListener("input", () => { + if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; + else { + const newInput = [...this.userInput]; + newInput[index] = inputField.value; + this.userInput = newInput; + } + }); const buttonContainer = document.createElement("div"); buttonContainer.classList.add("button-container"); for (const buttonName in this.buttonJSON) { @@ -1139,8 +1160,14 @@ button.style.display = "inline-block"; button.addEventListener("click", () => { this.lastPressBtn = buttonInfo.name; - this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; - this.closeOverlay(overlay); + if (this.askBoxInfo[1] == 1) this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; + else { + const newInput = [...this.userInput]; + newInput[index] = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; + this.userInput = newInput; + } + this.closeOverlay(overlay, hasDecreased); + hasDecreased = true; resolve(); }); buttonContainer.appendChild(button); @@ -1174,7 +1201,12 @@ } else { selectedOptions.push(label) } inputField.value = selectedOptions.length > 0 ? JSON.stringify(selectedOptions) : ""; } else { inputField.value = label } - this.userInput = inputField.value; + if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; + else { + const newInput = [...this.userInput]; + newInput[index] = inputField.value; + this.userInput = newInput; + } }); optionLabel.appendChild(optionRadio); optionLabel.appendChild(document.createTextNode(" " + label)); @@ -1209,7 +1241,12 @@ slider.addEventListener("input", () => { valueDisplay.textContent = slider.value; inputField.value = slider.value; - this.userInput = valueDisplay.textContent; + if (this.askBoxInfo[1] == 1) this.userInput = valueDisplay.textContent; + else { + const newInput = [...this.userInput]; + newInput[index] = valueDisplay.textContent; + this.userInput = newInput; + } }); for (const item of this.uiOrder) { switch (item) { @@ -1274,27 +1311,29 @@ }); } } - closeOverlay(overlay) { + closeOverlay(overlay, doneBefore) { if (this.askBoxInfo[0] < 2) this.isWaitingForInput = false; this.isDropdownOpen = false; - this.askBoxInfo[0]--; - let usedBG = document.querySelectorAll(".SP-ask-boxBG"); - usedBG = usedBG[usedBG.length - 1]; - // ^ Prioritizes Textboxes on Window - const index = this.activeOverlays.indexOf(overlay); - setTimeout(() => { - if (index !== -1) { - this.activeOverlays.splice(index, 1); - this.askBoxPromises.splice(index, 1); - } - delete this.activeUI[overlay]; - if (this.appendTarget[0] === "window") document.body.removeChild(overlay); - else vm.renderer.removeOverlay(overlay); - if (usedBG) { - if (usedBG.id === "window") document.body.removeChild(usedBG); - else vm.renderer.removeOverlay(usedBG); - } - }, this.Timeout * 1000); + if (!doneBefore) { + this.askBoxInfo[0]--; + let usedBG = document.querySelectorAll(".SP-ask-boxBG"); + usedBG = usedBG[usedBG.length - 1]; + // ^ Prioritizes Textboxes on Window + const index = this.activeOverlays.indexOf(overlay); + setTimeout(() => { + if (index !== -1) { + this.activeOverlays.splice(index, 1); + this.askBoxPromises.splice(index, 1); + } + delete this.activeUI[overlay]; + if (this.appendTarget[0] === "window") document.body.removeChild(overlay); + else vm.renderer.removeOverlay(overlay); + if (usedBG) { + if (usedBG.id === "window") document.body.removeChild(usedBG); + else vm.renderer.removeOverlay(usedBG); + } + }, this.Timeout * 1000); + } } setButton(args) { @@ -1321,16 +1360,19 @@ isDropdown() { return this.isDropdownOpen } - setMaxBoxCount(args) { this.askBoxInfo[1] = args.MAX } - - setTimeout(args) { - this.Timeout = args.TIME; - this.Condition = args.CONDITION; + setMaxBoxCount(args) { + this.askBoxInfo[1] = Scratch.Cast.toNumber(args.MAX); + if (this.askBoxInfo[1] > 1 && !Array.isArray(this.userInput)) this.userInput = [this.userInput]; } + setTimeout(args) { this.Timeout = Scratch.Cast.toNumber(args.TIME) } + reportTimeout() { return this.Timeout } - getUserInput() { return this.userInput === null ? "" : this.userInput } + getUserInput() { + if (this.askBoxInfo[1] > 1) return this.userInput === null ? "[]" : JSON.stringify(this.userInput); + else return this.userInput === null ? "" : this.userInput; + } getBoxInfo(args) { if (args.INFO.includes("button")) { From 170981b6176720c6267e32d9985e9cf0905d3f60 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Tue, 2 Jul 2024 01:12:32 -0700 Subject: [PATCH 39/46] Update Better-Input.js --- extensions/SharkPool/Better-Input.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 52da7fad2a..b7bb898c8d 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -1048,12 +1048,13 @@ this.activeOverlays = this.activeOverlays.filter((overlay) => !overlaysToRemove.includes(overlay)); this.activeUI = []; this.askBoxInfo[0] = 0; + this.isDropdownOpen = false; // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info const bugged = document.querySelectorAll(`[class^="SP-ask-box"]`); bugged.forEach((box) => { box.parentNode.removeChild(box) }); } - resetInput() { this.userInput = this.askBoxInfo[1] > 1 ? "[]" : "" } + resetInput() { this.userInput = this.askBoxInfo[1] > 1 ? [] : "" } askAndWaitForInput(args) { if (this.askBoxInfo[0] < this.askBoxInfo[1] ) { From 6d9248edacfef15f34d8d47b1867c553766d28ca Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 11 Aug 2024 12:04:57 -0700 Subject: [PATCH 40/46] Better-Input -- V4.2 --- extensions/SharkPool/Better-Input.js | 443 ++++++++++++--------------- 1 file changed, 189 insertions(+), 254 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index b7bb898c8d..8c9cfbbe9a 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -3,34 +3,31 @@ // Description: Expansion of the "ask and wait" Blocks // By: SharkPool -// Version V.4.1.1 +// Version V.4.2.0 (function (Scratch) { "use strict"; if (!Scratch.extensions.unsandboxed) throw new Error("Better Input must run unsandboxed"); const menuIconURI = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxMzQuMTc2MjgiIGhlaWdodD0iMTM0LjE3NjI4IiB2aWV3Qm94PSIwLDAsMTM0LjE3NjI4LDEzNC4xNzYyOCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE3Mi45MTE4NiwtMTEyLjkxMTg2KSI+PGcgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aXNQYWludGluZ0xheWVyJnF1b3Q7OnRydWV9IiBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNMTcyLjkxMTg2LDE4MGMwLC0zNy4wNTE3NiAzMC4wMzYzOCwtNjcuMDg4MTQgNjcuMDg4MTQsLTY3LjA4ODE0YzM3LjA1MTc2LDAgNjcuMDg4MTQsMzAuMDM2MzggNjcuMDg4MTQsNjcuMDg4MTRjMCwzNy4wNTE3NiAtMzAuMDM2MzgsNjcuMDg4MTQgLTY3LjA4ODE0LDY3LjA4ODE0Yy0zNy4wNTE3NiwwIC02Ny4wODgxNCwtMzAuMDM2MzggLTY3LjA4ODE0LC02Ny4wODgxNHoiIGZpbGw9IiM5NDAwZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjI0LjY2NTI2LDE1OC40NTE3aDI4LjA0MDY3djIxLjU0ODMxdjIxLjUwODQ4bC0yOC40Mzg5OCwtMC4wMzk4M2MtMjguMiwtMC4wNzk2NiAtMjguNDM4OTksLTAuMDc5NjcgLTI5LjMxNTI2LC0wLjU5NzQ2Yy0wLjQ3Nzk3LC0wLjI3ODgyIC0xLjExNTI1LC0wLjkxNjEgLTEuMzk0MDcsLTEuNDczNzNsLTAuNTU3NjMsLTAuOTU1OTN2LTE4LjQ0MTUzYzAsLTE3LjcyNDU4IDAuMDM5ODMsLTE4LjQ0MTUzIDAuNDc3OTcsLTE5LjM1NzYzYzAuNTk3NDYsLTEuMDc1NDIgMC45NTU5MywtMS40MzM5IDIuMTUwODUsLTEuODcyMDNjMC43NTY3OCwtMC4yMzg5OSA2LjE3MzczLC0wLjMxODY1IDI5LjAzNjQ0LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjEwMTcsMTc2LjA5NjYxYzAuMTU5MzIsMC4xNTkzMiAyLjU4ODk4LDYuMTMzOSAyLjU4ODk4LDYuMzMzMDVjMCwwLjE1OTMyIC0xLjE5NDkxLDAuMjM4OTggLTIuNzA4NDcsMC4yMzg5OGMtMi4wNzExOCwwIC0yLjY2ODY0LC0wLjA3OTY2IC0yLjU4ODk4LC0wLjMxODY1YzAuMDc5NjYsLTAuMTU5MzIgMC42NzcxMiwtMS42MzMwNSAxLjM5NDA3LC0zLjMwNTkzYzAuNzE2OTUsLTEuNjMzMDUgMS4zMTQ0LC0yLjk4NzI5IDEuMzE0NCwtMi45NDc0NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNjcuNjQyMzgsMTgwdi0yMS41ODgxM2w4LjI4NDc0LDAuMDc5NjZjNy44MDY3OCwwLjA3OTY2IDguMzI0NTgsMC4xMTk1IDkuMTIxMTksMC41OTc0NmMwLjQ3Nzk2LDAuMjc4ODIgMS4xMTUyNSwwLjkxNjEgMS4zOTQwNywxLjQ3MzczbDAuNTU3NjIsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC41NTc2MiwwLjk1NTkzYy0wLjI3ODgyLDAuNTU3NjMgLTAuOTE2MTEsMS4xOTQ5MSAtMS4zOTQwNywxLjQ3MzczYy0wLjgzNjQ0LDAuNTE3OCAtMS4zMTQ0MSwwLjUxNzggLTkuMTIxMTksMC41OTc0NmwtOC4yODQ3NCwwLjA3OTY2di0yMS41NDgzeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI0OS42Nzg4MiwxNDEuMDQ1NzZsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yNTEuMzcyNiwxNTguNDUxN3Y0My4wNTY3OGMwLDAgLTU1LjU0NDYzLC0wLjExOTUgLTU2LjQyMDksLTAuNjM3MjljLTAuNDc3OTcsLTAuMjc4ODIgLTEuMTE1MjUsLTAuOTE2MSAtMS4zOTQwNywtMS40NzM3M2wtMC41NTc2MywtMC45NTU5M3YtMTguNDQxNTNjMCwtMTcuNzI0NTggMC4wMzk4MywtMTguNDQxNTMgMC40Nzc5NywtMTkuMzU3NjNjMC41OTc0NiwtMS4wNzU0MiAwLjk1NTkzLC0xLjQzMzkgMi4xNTA4NSwtMS44NzIwM2MwLjc1Njc4LC0wLjIzODk5IDU1Ljc0Mzc4LC0wLjMxODY1IDU1Ljc0Mzc4LC0wLjMxODY1ek0yMTQuNjI3OTcsMTY4LjQ0OTE2Yy0wLjYzNzI5LDAuMzk4MyAtMS4zMTQ0MSwxLjc5MjM3IC01LjAxODY0LDkuOTk3NDZjLTQuNjIwMzQsMTAuMjM2NDQgLTQuODU5MzIsMTAuOTEzNTYgLTMuODIzNzIsMTIuMDI4ODJjMS4xNTUwOSwxLjIzNDc1IDIuOTQ3NDUsMS4yNzQ1NyAzLjk4MzA1LDAuMDM5ODNjMC4zMTg2NSwtMC4zOTgzIDAuNzk2NiwtMS4yNzQ1NyAxLjAzNTU5LC0xLjk1MTdsMC40MzgxNCwtMS4yMzQ3NWg0Ljc3OTY2aDQuNzc5NjZsMC41NTc2MywxLjQzMzljMC43MTY5NSwxLjk1MTcgMS40NzM3MywyLjYyODgyIDIuOTA3NjMsMi42Mjg4MmMwLjkxNjEsMCAxLjE5NDkxLC0wLjExOTQ5IDEuNzkyMzcsLTAuNzk2NjFjMC41MTc4LC0wLjU1NzYzIDAuNzE2OTUsLTEuMDM1NTkgMC43MTY5NSwtMS42NzI4OGMwLC0wLjYzNzI5IC0xLjE1NTA4LC0zLjU4NDc0IC0zLjc4MzksLTkuNDM5ODNjLTQuOTc4ODEsLTExLjE5MjM3IC00LjczOTg0LC0xMC43MTQ0MSAtNS41MzY0NSwtMTEuMTEyNzFjLTAuOTE2MSwtMC41MTc4IC0xLjkxMTg3LC0wLjQ3Nzk2IC0yLjgyNzk3LDAuMDc5NjZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMTYuMTAxNywxNzYuMDk2NjFjMC4xNTkzMiwwLjE1OTMyIDIuNTg4OTgsNi4xMzM5IDIuNTg4OTgsNi4zMzMwNWMwLDAuMTU5MzIgLTEuMTk0OTEsMC4yMzg5OCAtMi43MDg0NywwLjIzODk4Yy0yLjA3MTE4LDAgLTIuNjY4NjQsLTAuMDc5NjYgLTIuNTg4OTgsLTAuMzE4NjVjMC4wNzk2NiwtMC4xNTkzMiAwLjY3NzEyLC0xLjYzMzA1IDEuMzk0MDcsLTMuMzA1OTNjMC43MTY5NSwtMS42MzMwNSAxLjMxNDQsLTIuOTg3MjkgMS4zMTQ0LC0yLjk0NzQ2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjY4Ljk3NTcxLDE1OC40MTE4N2MwLDAgMTUuMjc1OTksMC4xOTkxNSAxNi4wNzI2LDAuNjc3MTJjMC40Nzc5NiwwLjI3ODgyIDEuMTE1MjUsMC45MTYxIDEuMzk0MDcsMS40NzM3M2wwLjU1NzYyLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNTU3NjIsMC45NTU5M2MtMC4yNzg4MiwwLjU1NzYzIC0wLjkxNjExLDEuMTk0OTEgLTEuMzk0MDcsMS40NzM3M2MtMC44MzY0NCwwLjUxNzggLTE2LjA3MjYsMC42NzcxMiAtMTYuMDcyNiwwLjY3NzEyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48L2c+PC9nPjwvc3ZnPg=="; - +"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMzQuMTc2IiBoZWlnaHQ9IjEzNC4xNzYiIHZpZXdCb3g9IjAgMCAxMzQuMTc2IDEzNC4xNzYiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTAgNjcuMDg4QzAgMzAuMDM2IDMwLjAzNiAwIDY3LjA4OCAwczY3LjA4OCAzMC4wMzYgNjcuMDg4IDY3LjA4OC0zMC4wMzYgNjcuMDg4LTY3LjA4OCA2Ny4wODhTMCAxMDQuMTQgMCA2Ny4wODgiIGZpbGw9IiM5NDAwZmYiLz48cGF0aCBkPSJtNzYuNzY3IDI4LjEzNCAxMC44MzQuMDRjMTAuNTE1LjA4IDEwLjgzNC4xMiAxMS41MS41OTcgMi40MyAxLjg3MiAyLjM5IDQuOTM5LS4xNTkgNi42NTItLjc1Ni41MTgtMS4xMTUuNTU3LTQuMzQxLjU1N2gtMy41MDV2NjIuMTc2aDMuNDY1YzMuOTQzIDAgNC45LjMxOCA1LjgxNSAxLjk1MSAxLjAzNiAxLjgzMy41MTggMy45NDQtMS4yNzQgNS4yNTgtLjY3Ny41MTgtLjk5Ni41MTgtMTEuNTExLjU5OGwtMTAuODM0LjA4LTEuMTE1LS41NThjLTEuMTU2LS42MzgtMi4xOTEtMi4xNTEtMi4xOTEtMy4zODYgMC0uODc2Ljk5Ni0yLjY2OSAxLjc5Mi0zLjI2Ni41OTgtLjQ3OCAxLjExNi0uNTE4IDQuMzQyLS41OThsMy42NjQtLjA4VjM2LjAybC0zLjY2NC0uMDhjLTMuMjI2LS4wOC0zLjc0NC0uMTE5LTQuMzQyLS41OTctLjc5Ni0uNTU4LTEuNzkyLTIuMzUtMS43OTItMy4yNjYgMC0xLjIzNS45OTYtMi43ODggMi4xOS0zLjM4NnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik01MS43NTMgNDUuNTRoMjguMDR2NDMuMDU2bC0yOC40MzgtLjA0Yy0yOC4yLS4wNzktMjguNDM5LS4wNzktMjkuMzE1LS41OTctLjQ3OC0uMjc5LTEuMTE2LS45MTYtMS4zOTQtMS40NzRsLS41NTgtLjk1NVY2Ny4wODhjMC0xNy43MjUuMDQtMTguNDQyLjQ3OC0xOS4zNTguNTk3LTEuMDc1Ljk1Ni0xLjQzNCAyLjE1LTEuODcyLjc1OC0uMjM5IDYuMTc1LS4zMTggMjkuMDM3LS4zMTh6bS0xMC4wMzcgOS45OTdjLS42MzcuMzk4LTEuMzE0IDEuNzkzLTUuMDE5IDkuOTk4LTQuNjIgMTAuMjM2LTQuODU5IDEwLjkxMy0zLjgyMyAxMi4wMjggMS4xNTUgMS4yMzUgMi45NDcgMS4yNzUgMy45ODMuMDQuMzE4LS4zOTguNzk2LTEuMjc0IDEuMDM1LTEuOTUxbC40MzgtMS4yMzVoOS41NmwuNTU3IDEuNDM0Yy43MTcgMS45NTEgMS40NzQgMi42MjkgMi45MDggMi42MjkuOTE2IDAgMS4xOTUtLjEyIDEuNzkyLS43OTcuNTE4LS41NTguNzE3LTEuMDM2LjcxNy0xLjY3M3MtMS4xNTUtMy41ODUtMy43ODQtOS40NGMtNC45NzgtMTEuMTkyLTQuNzQtMTAuNzE0LTUuNTM2LTExLjExMi0uOTE2LS41MTgtMS45MTItLjQ3OC0yLjgyOC4wOHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik00My4xOSA2My4xODVjLjE1OS4xNTkgMi41ODkgNi4xMzQgMi41ODkgNi4zMzMgMCAuMTU5LTEuMTk1LjIzOS0yLjcwOS4yMzktMi4wNzEgMC0yLjY2OC0uMDgtMi41ODktLjMxOS4wOC0uMTYuNjc3LTEuNjMzIDEuMzk0LTMuMzA2LjcxNy0xLjYzMyAxLjMxNS0yLjk4NyAxLjMxNS0yLjk0N3ptNTEuNTQgMy45MDNWNDUuNWw4LjI4NS4wOGM3LjgwNy4wOCA4LjMyNS4xMTkgOS4xMjEuNTk3LjQ3OC4yNzkgMS4xMTYuOTE2IDEuMzk0IDEuNDc0bC41NTguOTU2Vjg1LjUzbC0uNTU4Ljk1NWMtLjI3OC41NTgtLjkxNiAxLjE5NS0xLjM5NCAxLjQ3NC0uODM2LjUxOC0xLjMxNC41MTgtOS4xMi41OThsLTguMjg2LjA4eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0ibTc2Ljc2NyAyOC4xMzQgMTAuODM0LjA0YzEwLjUxNS4wOCAxMC44MzQuMTIgMTEuNTEuNTk3IDIuNDMgMS44NzIgMi4zOSA0LjkzOS0uMTU5IDYuNjUyLS43NTYuNTE4LTEuMTE1LjU1Ny00LjM0MS41NTdoLTMuNTA1djYyLjE3NmgzLjQ2NWMzLjk0MyAwIDQuOS4zMTggNS44MTUgMS45NTEgMS4wMzYgMS44MzMuNTE4IDMuOTQ0LTEuMjc0IDUuMjU4LS42NzcuNTE4LS45OTYuNTE4LTExLjUxMS41OThsLTEwLjgzNC4wOC0xLjExNS0uNTU4Yy0xLjE1Ni0uNjM4LTIuMTkxLTIuMTUxLTIuMTkxLTMuMzg2IDAtLjg3Ni45OTYtMi42NjkgMS43OTItMy4yNjYuNTk4LS40NzggMS4xMTYtLjUxOCA0LjM0Mi0uNTk4bDMuNjY0LS4wOFYzNi4wMmwtMy42NjQtLjA4Yy0zLjIyNi0uMDgtMy43NDQtLjExOS00LjM0Mi0uNTk3LS43OTYtLjU1OC0xLjc5Mi0yLjM1LTEuNzkyLTMuMjY2IDAtMS4yMzUuOTk2LTIuNzg4IDIuMTktMy4zODZ6IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTc4LjQ2MSA0NS41NHY0My4wNTZzLTU1LjU0NS0uMTE5LTU2LjQyMS0uNjM3Yy0uNDc4LS4yNzktMS4xMTYtLjkxNi0xLjM5NC0xLjQ3NGwtLjU1OC0uOTU1VjY3LjA4OGMwLTE3LjcyNS4wNC0xOC40NDIuNDc4LTE5LjM1OC41OTctMS4wNzUuOTU2LTEuNDM0IDIuMTUtMS44NzIuNzU4LS4yMzkgNTUuNzQ1LS4zMTggNTUuNzQ1LS4zMThtLTM2Ljc0NSA5Ljk5N2MtLjYzNy4zOTgtMS4zMTQgMS43OTMtNS4wMTkgOS45OTgtNC42MiAxMC4yMzYtNC44NTkgMTAuOTEzLTMuODIzIDEyLjAyOCAxLjE1NSAxLjIzNSAyLjk0NyAxLjI3NSAzLjk4My4wNC4zMTgtLjM5OC43OTYtMS4yNzQgMS4wMzUtMS45NTFsLjQzOC0xLjIzNWg5LjU2bC41NTcgMS40MzRjLjcxNyAxLjk1MSAxLjQ3NCAyLjYyOSAyLjkwOCAyLjYyOS45MTYgMCAxLjE5NS0uMTIgMS43OTItLjc5Ny41MTgtLjU1OC43MTctMS4wMzYuNzE3LTEuNjczcy0xLjE1NS0zLjU4NS0zLjc4NC05LjQ0Yy00Ljk3OC0xMS4xOTItNC43NC0xMC43MTQtNS41MzYtMTEuMTEyLS45MTYtLjUxOC0xLjkxMi0uNDc4LTIuODI4LjA4IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTQzLjE5IDYzLjE4NWMuMTU5LjE1OSAyLjU4OSA2LjEzNCAyLjU4OSA2LjMzMyAwIC4xNTktMS4xOTUuMjM5LTIuNzA5LjIzOS0yLjA3MSAwLTIuNjY4LS4wOC0yLjU4OS0uMzE5LjA4LS4xNi42NzctMS42MzMgMS4zOTQtMy4zMDYuNzE3LTEuNjMzIDEuMzE1LTIuOTg3IDEuMzE1LTIuOTQ3TTk2LjA2NCA0NS41czE1LjI3Ni4xOTkgMTYuMDcyLjY3N2MuNDc4LjI3OSAxLjExNi45MTYgMS4zOTQgMS40NzRsLjU1OC45NTZWODUuNTNsLS41NTguOTU1Yy0uMjc4LjU1OC0uOTE2IDEuMTk1LTEuMzk0IDEuNDc0LS44MzYuNTE4LTE2LjA3Mi42NzctMTYuMDcyLjY3N3oiIGZpbGw9IiNmZmYiLz48L2c+PC9zdmc+"; const blockIconURI = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3OS4zNjMxMyIgaGVpZ2h0PSI4Ny45MjE0OSIgdmlld0JveD0iMCwwLDc5LjM2MzEzLDg3LjkyMTQ5Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAwLjMxODQzLC0xMzYuMDQxNDMpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzIuNjcxMTksMTgwLjAwMDAzdjIxLjU0ODNsLTExLjcwNjUyLC0wLjA3OTY2Yy0xMS4wMzExNiwtMC4wNzk2NiAtMTEuNzA2NTQsLTAuMDc5NjYgLTEyLjg4ODQ1LC0wLjU5NzQ2Yy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTYgMS44NTcyOSwtMC41MTc4IDEyLjg4ODQ1LC0wLjU5NzQ2bDExLjcwNjUyLC0wLjA3OTY2djIxLjU4ODEzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzAuNzg3MTYsMjAxLjU0ODMzYzAsMCAtMjEuNTI5MDQsLTAuMTU5MzIgLTIyLjcxMDk0LC0wLjY3NzEyYy0wLjY3NTM3LC0wLjI3ODgyIC0xLjU3NTg3LC0wLjkxNjEgLTEuOTY5ODUsLTEuNDczNzNsLTAuNzg3OTMsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjc4NzkzLC0wLjk1NTkzYzAuMzkzOTgsLTAuNTU3NjMgMS4yOTQ0OCwtMS4xOTQ5MSAxLjk2OTg1LC0xLjQ3MzczYzEuMTI1NjMsLTAuNDc3OTcgMjIuNzEwOTQsLTAuNjc3MTIgMjIuNzEwOTQsLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMjQ3LjMyODgxLDE4MC4wMDAwMXYtMjEuNTg4MTNsMTEuNzA2NTIsMC4wNzk2NmMxMS4wMzExNiwwLjA3OTY2IDExLjc2MjgyLDAuMTE5NSAxMi44ODg0NSwwLjU5NzQ2YzAuNjc1MzcsMC4yNzg4MiAxLjU3NTg3LDAuOTE2MSAxLjk2OTg1LDEuNDczNzNsMC43ODc5MywwLjk1NTkzdjE4LjQ4MTM2djE4LjQ0MTUzbC0wLjc4NzkzLDAuOTU1OTNjLTAuMzkzOTgsMC41NTc2MyAtMS4yOTQ0OCwxLjE5NDkxIC0xLjk2OTg1LDEuNDczNzNjLTEuMTgxOTEsMC41MTc4IC0xLjg1NzI5LDAuNTE3OCAtMTIuODg4NDUsMC41OTc0NmwtMTEuNzA2NTIsMC4wNzk2NnYtMjEuNTQ4M3oiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yNDkuMjEyODQsMTU4LjQxMTg4YzAsMCAyMS41ODUzMiwwLjE5OTE1IDIyLjcxMDk0LDAuNjc3MTJjMC42NzUzNywwLjI3ODgyIDEuNTc1ODcsMC45MTYxIDEuOTY5ODUsMS40NzM3M2wwLjc4NzkzLDAuOTU1OTN2MTguNDgxMzZ2MTguNDQxNTNsLTAuNzg3OTMsMC45NTU5M2MtMC4zOTM5OCwwLjU1NzYzIC0xLjI5NDQ4LDEuMTk0OTEgLTEuOTY5ODUsMS40NzM3M2MtMS4xODE5MSwwLjUxNzggLTIyLjcxMDk0LDAuNjc3MTIgLTIyLjcxMDk0LDAuNjc3MTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMjkuNTk1NTYsMTQxLjA0NTc3bDEwLjgzMzksMC4wMzk4M2MxMC41MTUyNiwwLjA3OTY2IDEwLjgzMzksMC4xMTk0OSAxMS41MTEwMiwwLjU5NzQ1YzIuNDI5NjYsMS44NzIwNCAyLjM4OTgzLDQuOTM4OTkgLTAuMTU5MzMsNi42NTE2OWMtMC43NTY3OCwwLjUxNzggLTEuMTE1MjUsMC41NTc2MyAtNC4zNDE1MiwwLjU1NzYzaC0zLjUwNTA5djMxLjEwNzYzdjMxLjA2Nzc5aDMuNDY1MjZjMy45NDMyMiwwIDQuODk5MTYsMC4zMTg2NSA1LjgxNTI2LDEuOTUxN2MxLjAzNTYsMS44MzIyIDAuNTE3OCwzLjk0MzIzIC0xLjI3NDU4LDUuMjU3NjNjLTAuNjc3MTIsMC41MTc4IC0wLjk5NTc2LDAuNTE3OCAtMTEuNTExMDIsMC41OTc0NWwtMTAuODMzOSwwLjA3OTY2bC0xLjExNTI1LC0wLjU1NzYzYy0xLjE1NTA5LC0wLjYzNzI5IC0yLjE5MDY4LC0yLjE1MDg1IC0yLjE5MDY4LC0zLjM4NTZjMCwtMC44NzYyNyAwLjk5NTc3LC0yLjY2ODY0IDEuNzkyMzcsLTMuMjY2MWMwLjU5NzQ2LC0wLjQ3Nzk3IDEuMTE1MjUsLTAuNTE3OCA0LjM0MTUyLC0wLjU5NzQ1bDMuNjY0NCwtMC4wNzk2N3YtMzEuMDY3Nzl2LTMxLjA2Nzc5bC0zLjY2NDQsLTAuMDc5NjdjLTMuMjI2MjcsLTAuMDc5NjYgLTMuNzQ0MDYsLTAuMTE5NDkgLTQuMzQxNTIsLTAuNTk3NDVjLTAuNzk2NjEsLTAuNTU3NjMgLTEuNzkyMzcsLTIuMzUgLTEuNzkyMzcsLTMuMjY2MWMwLC0xLjIzNDc1IDAuOTk1NzYsLTIuNzg4MTQgMi4xOTA2OCwtMy4zODU2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIyOS41OTU1NiwxNDEuMDQ1NzdsMTAuODMzOSwwLjAzOTgzYzEwLjUxNTI2LDAuMDc5NjYgMTAuODMzOSwwLjExOTQ5IDExLjUxMTAyLDAuNTk3NDVjMi40Mjk2NiwxLjg3MjA0IDIuMzg5ODMsNC45Mzg5OSAtMC4xNTkzMyw2LjY1MTY5Yy0wLjc1Njc4LDAuNTE3OCAtMS4xMTUyNSwwLjU1NzYzIC00LjM0MTUyLDAuNTU3NjNoLTMuNTA1MDl2MzEuMTA3NjN2MzEuMDY3NzloMy40NjUyNmMzLjk0MzIyLDAgNC44OTkxNiwwLjMxODY1IDUuODE1MjYsMS45NTE3YzEuMDM1NiwxLjgzMjIgMC41MTc4LDMuOTQzMjMgLTEuMjc0NTgsNS4yNTc2M2MtMC42NzcxMiwwLjUxNzggLTAuOTk1NzYsMC41MTc4IC0xMS41MTEwMiwwLjU5NzQ1bC0xMC44MzM5LDAuMDc5NjZsLTEuMTE1MjUsLTAuNTU3NjNjLTEuMTU1MDksLTAuNjM3MjkgLTIuMTkwNjgsLTIuMTUwODUgLTIuMTkwNjgsLTMuMzg1NmMwLC0wLjg3NjI3IDAuOTk1NzcsLTIuNjY4NjQgMS43OTIzNywtMy4yNjYxYzAuNTk3NDYsLTAuNDc3OTcgMS4xMTUyNSwtMC41MTc4IDQuMzQxNTIsLTAuNTk3NDVsMy42NjQ0LC0wLjA3OTY3di0zMS4wNjc3OXYtMzEuMDY3NzlsLTMuNjY0NCwtMC4wNzk2N2MtMy4yMjYyNywtMC4wNzk2NiAtMy43NDQwNiwtMC4xMTk0OSAtNC4zNDE1MiwtMC41OTc0NWMtMC43OTY2MSwtMC41NTc2MyAtMS43OTIzNywtMi4zNSAtMS43OTIzNywtMy4yNjYxYzAsLTEuMjM0NzUgMC45OTU3NiwtMi43ODgxNCAyLjE5MDY4LC0zLjM4NTZ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OS4zNjMiIGhlaWdodD0iODcuOTIxIiB2aWV3Qm94PSIwIDAgNzkuMzYzIDg3LjkyMSI+PGcgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIj48cGF0aCBkPSJNMzIuMzUzIDQzLjk1OXYyMS41NDhsLTExLjcwNi0uMDhjLTExLjAzMS0uMDc5LTExLjcwNy0uMDc5LTEyLjg4OS0uNTk3LS42NzUtLjI3OS0xLjU3Ni0uOTE2LTEuOTctMS40NzRMNSA2Mi40MDFWMjUuNDc4bC43ODgtLjk1NmMuMzk0LS41NTggMS4yOTUtMS4xOTUgMS45Ny0xLjQ3NCAxLjEyNi0uNDc4IDEuODU4LS41MTggMTIuODg5LS41OTdsMTEuNzA2LS4wOHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMC40NjkgNjUuNTA3cy0yMS41MjktLjE1OS0yMi43MS0uNjc3Yy0uNjc2LS4yNzktMS41NzctLjkxNi0xLjk3LTEuNDc0TDUgNjIuNDAxVjI1LjQ3OGwuNzg4LS45NTZjLjM5NC0uNTU4IDEuMjk1LTEuMTk1IDEuOTctMS40NzQgMS4xMjYtLjQ3OCAyMi43MTEtLjY3NyAyMi43MTEtLjY3N3oiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNNDcuMDExIDQzLjk1OVYyMi4zNzFsMTEuNzA2LjA4YzExLjAzMS4wOCAxMS43NjMuMTE5IDEyLjg4OS41OTcuNjc1LjI3OSAxLjU3Ni45MTYgMS45NyAxLjQ3NGwuNzg4Ljk1NnYzNi45MjNsLS43ODguOTU1Yy0uMzk0LjU1OC0xLjI5NSAxLjE5NS0xLjk3IDEuNDc0LTEuMTgyLjUxOC0xLjg1OC41MTgtMTIuODg5LjU5OGwtMTEuNzA2LjA4eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTQ4Ljg5NSAyMi4zNzFzMjEuNTg1LjE5OSAyMi43MS42NzdjLjY3Ni4yNzkgMS41NzcuOTE2IDEuOTcgMS40NzRsLjc4OS45NTZ2MzYuOTIzbC0uNzg4Ljk1NWMtLjM5NC41NTgtMS4yOTUgMS4xOTUtMS45NyAxLjQ3NC0xLjE4Mi41MTgtMjIuNzExLjY3Ny0yMi43MTEuNjc3eiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Im0yOS4yNzggNS4wMDUgMTAuODMzLjA0YzEwLjUxNi4wOCAxMC44MzQuMTIgMTEuNTExLjU5NyAyLjQzIDEuODcyIDIuMzkgNC45MzktLjE1OSA2LjY1Mi0uNzU3LjUxOC0xLjExNS41NTctNC4zNDEuNTU3aC0zLjUwNXY2Mi4xNzZoMy40NjVjMy45NDMgMCA0Ljg5OS4zMTggNS44MTUgMS45NTEgMS4wMzYgMS44MzMuNTE4IDMuOTQ0LTEuMjc1IDUuMjU4LS42NzcuNTE4LS45OTUuNTE4LTExLjUxLjU5OGwtMTAuODM0LjA4LTEuMTE2LS41NThjLTEuMTU1LS42MzgtMi4xOS0yLjE1MS0yLjE5LTMuMzg2IDAtLjg3Ni45OTUtMi42NjkgMS43OTItMy4yNjYuNTk3LS40NzggMS4xMTUtLjUxOCA0LjM0Mi0uNTk4bDMuNjY0LS4wOFYxMi44OTFsLTMuNjY0LS4wOGMtMy4yMjctLjA4LTMuNzQ1LS4xMTktNC4zNDItLjU5Ny0uNzk3LS41NTgtMS43OTItMi4zNS0xLjc5Mi0zLjI2NiAwLTEuMjM1Ljk5NS0yLjc4OCAyLjE5LTMuMzg2eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0ibTI5LjI3OCA1LjAwNSAxMC44MzMuMDRjMTAuNTE2LjA4IDEwLjgzNC4xMiAxMS41MTEuNTk3IDIuNDMgMS44NzIgMi4zOSA0LjkzOS0uMTU5IDYuNjUyLS43NTcuNTE4LTEuMTE1LjU1Ny00LjM0MS41NTdoLTMuNTA1djYyLjE3NmgzLjQ2NWMzLjk0MyAwIDQuODk5LjMxOCA1LjgxNSAxLjk1MSAxLjAzNiAxLjgzMy41MTggMy45NDQtMS4yNzUgNS4yNTgtLjY3Ny41MTgtLjk5NS41MTgtMTEuNTEuNTk4bC0xMC44MzQuMDgtMS4xMTYtLjU1OGMtMS4xNTUtLjYzOC0yLjE5LTIuMTUxLTIuMTktMy4zODYgMC0uODc2Ljk5NS0yLjY2OSAxLjc5Mi0zLjI2Ni41OTctLjQ3OCAxLjExNS0uNTE4IDQuMzQyLS41OThsMy42NjQtLjA4VjEyLjg5MWwtMy42NjQtLjA4Yy0zLjIyNy0uMDgtMy43NDUtLjExOS00LjM0Mi0uNTk3LS43OTctLjU1OC0xLjc5Mi0yLjM1LTEuNzkyLTMuMjY2IDAtMS4yMzUuOTk1LTIuNzg4IDIuMTktMy4zODZ6IiBmaWxsPSIjZmZmIi8+PC9nPjwvc3ZnPg=="; const formatIcon = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIxNTAuOTAzNTUiIGhlaWdodD0iOTUuNSIgdmlld0JveD0iMCwwLDE1MC45MDM1NSw5NS41Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTY0LjU0ODIyLC0xMzIuMjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMzkuNzQxOTcsMjAxLjgxODIzYzAsMCAtNDAuMjY2OTcsLTAuMTU5MzIgLTQxLjU1OTI5LC0wLjY3NzEyYy0wLjczODQ2LC0wLjI3ODgyIC0xLjcyMzA5LC0wLjkxNjEgLTIuMTUzODcsLTEuNDczNzNsLTAuODYxNTQsLTAuOTU1OTN2LTE4LjQ0MTUzdi0xOC40ODEzNmwwLjg2MTU0LC0wLjk1NTkzYzAuNDMwNzksLTAuNTU3NjMgMS40MTU0MSwtMS4xOTQ5MSAyLjE1Mzg3LC0xLjQ3MzczYzEuMjMwNzksLTAuNDc3OTYgNDEuNTU5MjksLTAuNjc3MTIgNDEuNTU5MjksLTAuNjc3MTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIzNC4wOTEzNiwxNTguNjgxNzhjMCwwIDQyLjY2MTg0LDAuMTk5MTYgNDMuODkyNjIsMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDMuODkyNjIsMC42NzcxMiAtNDMuODkyNjIsMC42NzcxMnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzYuMTUxNCwxNTguNjgxNzhjMCwwIDQwLjYwMTgxLDAuMTk5MTUgNDEuODMyNTksMC42NzcxMmMwLjczODQ2LDAuMjc4ODIgMS43MjMwOSwwLjkxNjEgMi4xNTM4NywxLjQ3MzczbDAuODYxNTQsMC45NTU5M3YxOC40ODEzNnYxOC40NDE1M2wtMC44NjE1NCwwLjk1NTkzYy0wLjQzMDc5LDAuNTU3NjMgLTEuNDE1NDEsMS4xOTQ5MSAtMi4xNTM4NywxLjQ3MzczYy0xLjI5MjMyLDAuNTE3OCAtNDEuODMyNTksMC42NzcxMiAtNDEuODMyNTksMC42NzcxMnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIzNy42ODE5MywyMDEuODE4MjNjMCwwIC0zOC4yMDY5NCwtMC4xNTkzMiAtMzkuNDk5MjYsLTAuNjc3MTJjLTAuNzM4NDYsLTAuMjc4ODIgLTEuNzIzMDksLTAuOTE2MSAtMi4xNTM4NywtMS40NzM3M2wtMC44NjE1NCwtMC45NTU5M3YtMTguNDQxNTN2LTE4LjQ4MTM2bDAuODYxNTQsLTAuOTU1OTNjMC40MzA3OSwtMC41NTc2MyAxLjQxNTQxLC0xLjE5NDkxIDIuMTUzODcsLTEuNDczNzNjMS4yMzA3OCwtMC40Nzc5NyAzOS40OTkyNiwtMC42NzcxMiAzOS40OTkyNiwtMC42NzcxMnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0xNjkuNTQ4MjIsMTU0LjQwNzUydi0xNy4xNTc1MmgxNy4xNTc1MnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTY5LjU0ODIzLDE1NC40MDc1MnYtMTcuMTU3NTJoMTcuMTU3NTJ6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0zMTAuNDUxNzgsMjA1LjU5MjQ4djE3LjE1NzUyaC0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xODYuNzA1NzYsMjIyLjc1aC0xNy4xNTc1MnYtMTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTI5My4yOTQyNSwxMzcuMjVoMTcuMTU3NTJ2MTcuMTU3NTJ6IiBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpbmRleCZxdW90OzpudWxsfSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTE4Ni43MDU3NiwyMjIuNzVoLTE3LjE1NzUydi0xNy4xNTc1MnoiIGRhdGEtcGFwZXItZGF0YT0ieyZxdW90O2luZGV4JnF1b3Q7Om51bGx9IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0yOTMuMjk0MjUsMTM3LjI1aDE3LjE1NzUydjE3LjE1NzUyeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7aW5kZXgmcXVvdDs6bnVsbH0iIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PHBhdGggZD0iTTIzNi4yNjY0NCwxNjUuNjY5ODVjMS4xODI3MiwtMC43MTk5MSAyLjQ4NDMxLC0wLjc3MTMzIDMuNjY3MDMsLTAuMTAyODNjMS4wMjg0NSwwLjUxNDIyIDAuNzc2MzksLTAuMDQwOTQgNy4yMDQyMSwxNC40MDg4YzMuMzkzOSw3LjU1OTEzIDQuODY5NjUsMTEuNDA4NTMgNC44Njk2NSwxMi4yMzEyOWMwLDAuODIyNzYgLTAuMjYyMzgsMS40NDUyOSAtMC45MzA4OCwyLjE2NTIxYy0wLjc3MTM0LDAuODc0MTkgLTEuMTM3ODQsMS4wMzM3NCAtMi4zMjA1NSwxLjAzMzc0Yy0xLjg1MTIxLDAgLTIuODk4MjIsLTAuOTgyNTUgLTMuODIzODIsLTMuNTAyMjdsLTAuNjUyODgsLTEuNzQwOWwtNi4yMDUwNSwwLjAwOTg1bC02LjIwNSwtMC4wMDk5bC0wLjQ5ODQ5LDEuNDgzODZjLTAuMzA4NTQsMC44NzQyIC0wLjk5MDc4LDIuMTE2OTMgLTEuNDAyMTcsMi42MzExNWMtMS4zMzcsMS41OTQwOSAtMy42NjMxMywxLjUzMzU5IC01LjE1NDM5LC0wLjA2MDUxYy0xLjMzNywtMS40Mzk4NCAtMS4wNDcyOSwtMi4zNzMyOCA0LjkxNzczLC0xNS41ODg4OGM0Ljc4MjI5LC0xMC41OTMwNiA1LjcxMTg0LC0xMi40NDQ0MSA2LjUzNDYsLTEyLjk1ODYzeiIgZGF0YS1wYXBlci1kYXRhPSJ7JnF1b3Q7bm9Ib3ZlciZxdW90OzpmYWxzZSwmcXVvdDtvcmlnSXRlbSZxdW90OzpbJnF1b3Q7UGF0aCZxdW90Oyx7JnF1b3Q7YXBwbHlNYXRyaXgmcXVvdDs6dHJ1ZSwmcXVvdDtzZWdtZW50cyZxdW90OzpbW1szMzcuMjU1OTQsMTk4LjIzMTY1XSxbMCwwXSxbLTEuMjc0NTgsMC43OTY2XV0sW1szMjcuMjE4NjYsMjE4LjIyNjU3XSxbNy40MDg0NiwtMTYuNDEwMThdLFstOS4yNDA2OCwyMC40NzI4OF1dLFtbMzE5LjU3MTIyLDI0Mi4yODQyMV0sWy0yLjA3MTIsLTIuMjMwNTJdLFsyLjMxMDE4LDIuNDY5NV1dLFtbMzI3LjUzNzMyLDI0Mi4zNjM4N10sWy0yLjA3MTIsMi40Njk0OF0sWzAuNjM3MywtMC43OTY2XV0sW1szMjkuNjA4NSwyMzguNDYwNDddLFstMC40Nzc5OCwxLjM1NDI2XSxbMCwwXV0sWzMzMC40ODQ3OCwyMzUuOTkwOTddLFszNDAuMDQ0MSwyMzUuOTkwOTddLFszNDkuNjAzNDIsMjM1Ljk5MDk3XSxbWzM1MC43MTg2OCwyMzguODU4NzddLFswLDBdLFsxLjQzMzksMy45MDM0XV0sW1szNTYuNTMzOTQsMjQ0LjExNjQxXSxbLTIuODY3OCwwXSxbMS44MzIyLDBdXSxbWzM2MC4xMTg2OCwyNDIuNTIzMTldLFstMS4xOTQ5MiwxLjM1NDI0XSxbMS4wMzU2LC0xLjExNTI2XV0sW1szNjEuNTUyNTgsMjM5LjE3NzQzXSxbMCwxLjI3NDU4XSxbMCwtMS4yNzQ1OF1dLFtbMzUzLjk4NDc4LDIyMC4yOTc3N10sWzUuMjU3NjQsMTEuNzEwMThdLFstOS45NTc2MiwtMjIuMzg0NzRdXSxbWzM0Mi45MTE4OCwxOTguMDcyMzVdLFsxLjU5MzIyLDAuNzk2Nl0sWy0xLjgzMjIsLTEuMDM1Nl1dLFtbMzM3LjI1NTk0LDE5OC4yMzE2N10sWzEuODMyMiwtMS4xMTUyNF0sWzAsMF1dXSwmcXVvdDtjbG9zZWQmcXVvdDs6dHJ1ZSwmcXVvdDtmaWxsQ29sb3ImcXVvdDs6WzAsMCwwLDFdfV19IiBmaWxsPSIjNjkwMGI0IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PHBhdGggZD0iTTIzOC4xNzcwNCwxNzUuNjA3MDJjMC4yMDU2OSwwLjIwNTY5IDMuMzQyNDYsNy45MTkwOCAzLjM0MjQ2LDguMTc2MTljMCwwLjIwNTY5IC0xLjU0MjY3LDAuMzA4NTMgLTMuNDk2NzMsMC4zMDg1M2MtMi42NzM5NywwIC0zLjQ0NTMxLC0wLjEwMjg0IC0zLjM0MjQ2LC0wLjQxMTM5YzAuMTAyODQsLTAuMjA1NjkgMC44NzQxOSwtMi4xMDgzMiAxLjc5OTc5LC00LjI2ODA3YzAuOTI1NjEsLTIuMTA4MzIgMS42OTY5NCwtMy44NTY3IDEuNjk2OTQsLTMuODA1Mjd6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; - +"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTAuOTA0IiBoZWlnaHQ9Ijk1LjUiIHZpZXdCb3g9IjAgMCAxNTAuOTA0IDk1LjUiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTc1LjE5NCA2OS41NjhzLTQwLjI2Ny0uMTYtNDEuNTYtLjY3N2MtLjczOC0uMjc5LTEuNzIyLS45MTYtMi4xNTMtMS40NzRsLS44NjItLjk1NlYyOS41NGwuODYyLS45NTZjLjQzLS41NTggMS40MTUtMS4xOTUgMi4xNTQtMS40NzQgMS4yMy0uNDc4IDQxLjU1OS0uNjc3IDQxLjU1OS0uNjc3eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTY5LjU0MyAyNi40MzJzNDIuNjYyLjE5OSA0My44OTMuNjc3Yy43MzguMjc5IDEuNzIzLjkxNiAyLjE1NCAxLjQ3NGwuODYxLjk1NnYzNi45MjJsLS44NjEuOTU2Yy0uNDMuNTU4LTEuNDE2IDEuMTk1LTIuMTU0IDEuNDc0LTEuMjkyLjUxOC00My44OTMuNjc3LTQzLjg5My42Nzd6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNNzEuNjAzIDI2LjQzMnM0MC42MDIuMTk5IDQxLjgzMy42NzdjLjczOC4yNzkgMS43MjMuOTE2IDIuMTU0IDEuNDc0bC44NjEuOTU2djM2LjkyMmwtLjg2MS45NTZjLS40My41NTgtMS40MTYgMS4xOTUtMi4xNTQgMS40NzQtMS4yOTIuNTE4LTQxLjgzMy42NzctNDEuODMzLjY3N3oiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNNzMuMTM0IDY5LjU2OHMtMzguMjA3LS4xNi0zOS41LS42NzdjLS43MzgtLjI3OS0xLjcyMi0uOTE2LTIuMTUzLTEuNDc0bC0uODYyLS45NTZWMjkuNTRsLjg2Mi0uOTU2Yy40My0uNTU4IDEuNDE1LTEuMTk1IDIuMTU0LTEuNDc0IDEuMjMtLjQ3OCAzOS40OTktLjY3NyAzOS40OTktLjY3N3oiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNNSAyMi4xNThWNWgxNy4xNTh6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMTQ1LjkwNCA3My4zNDJWOTAuNWgtMTcuMTU4eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTUgMjIuMTU4VjVoMTcuMTU4eiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xNDUuOTA0IDczLjM0MlY5MC41aC0xNy4xNTh6IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTIyLjE1OCA5MC41SDVWNzMuMzQyek0xMjguNzQ2IDVoMTcuMTU4djE3LjE1OHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMi4xNTggOTAuNUg1VjczLjM0MnpNMTI4Ljc0NiA1aDE3LjE1OHYxNy4xNTh6IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTcxLjcxOCAzMy40MmMxLjE4My0uNzIgMi40ODUtLjc3MSAzLjY2Ny0uMTAzIDEuMDI5LjUxNC43NzctLjA0IDcuMjA1IDE0LjQwOSAzLjM5NCA3LjU1OSA0Ljg3IDExLjQwOCA0Ljg3IDEyLjIzMXMtLjI2MyAxLjQ0NS0uOTMyIDIuMTY1Yy0uNzcuODc1LTEuMTM3IDEuMDM0LTIuMzIgMS4wMzQtMS44NTEgMC0yLjg5OC0uOTgyLTMuODI0LTMuNTAybC0uNjUzLTEuNzQxLTYuMjA1LjAxLTYuMjA1LS4wMS0uNDk4IDEuNDg0Yy0uMzA5Ljg3NC0uOTkxIDIuMTE3LTEuNDAzIDIuNjMtMS4zMzcgMS41OTUtMy42NjMgMS41MzQtNS4xNTQtLjA2LTEuMzM3LTEuNDQtMS4wNDctMi4zNzMgNC45MTgtMTUuNTg5IDQuNzgyLTEwLjU5MyA1LjcxMi0xMi40NDQgNi41MzQtMTIuOTU4IiBmaWxsPSIjNjkwMGI0Ii8+PHBhdGggZD0iTTczLjYyOSA0My4zNTdjLjIwNi4yMDYgMy4zNDMgNy45MiAzLjM0MyA4LjE3NiAwIC4yMDYtMS41NDMuMzA5LTMuNDk3LjMwOS0yLjY3NCAwLTMuNDQ2LS4xMDMtMy4zNDMtLjQxMi4xMDMtLjIwNS44NzQtMi4xMDggMS44LTQuMjY4LjkyNi0yLjEwOCAxLjY5Ny0zLjg1NiAxLjY5Ny0zLjgwNSIgZmlsbD0iI2ZmZiIvPjwvZz48L3N2Zz4="; const colorIcon = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI3NS41MzUxNyIgaGVpZ2h0PSI3MS40OTc0NiIgdmlld0JveD0iMCwwLDc1LjUzNTE3LDcxLjQ5NzQ2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjAyLjIzMjQxLC0xNDQuMjUxMjcpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDIsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMzkuODQ0NzEsMTk0LjI4NzI5YzAsLTkuMDkxNDEgNy4zNzAwNCwtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNDEsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNDEsMCAtMTYuNDYxNDQsLTcuMzcwMDMgLTE2LjQ2MTQ0LC0xNi40NjE0NHoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0yMjMuNTM4NTYsMTY1LjcxMjcxYzAsLTkuMDkxNDEgNy4zNzAwMywtMTYuNDYxNDQgMTYuNDYxNDQsLTE2LjQ2MTQ0YzkuMDkxNCwwIDE2LjQ2MTQ0LDcuMzcwMDQgMTYuNDYxNDQsMTYuNDYxNDRjMCw5LjA5MTQxIC03LjM3MDAzLDE2LjQ2MTQ0IC0xNi40NjE0NCwxNi40NjE0NGMtOS4wOTE0LDAgLTE2LjQ2MTQ0LC03LjM3MDAzIC0xNi40NjE0NCwtMTYuNDYxNDR6IiBmaWxsPSIjMDBmZjAxIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0ibm9uZSIvPjxwYXRoIGQ9Ik0yMDcuMjMyNDEsMTk0LjI4NzI5YzAsLTkuMDkxNCA3LjM3MDA0LC0xNi40NjE0NCAxNi40NjE0NCwtMTYuNDYxNDRjOS4wOTE0LDAgMTYuNDYxNDQsNy4zNzAwNCAxNi40NjE0NCwxNi40NjE0NGMwLDkuMDkxNCAtNy4zNzAwNCwxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iI2ZmMDAwMCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48cGF0aCBkPSJNMjM5Ljg0NDcxLDE5NC4yODcyOWMwLC05LjA5MTQxIDcuMzcwMDMsLTE2LjQ2MTQ0IDE2LjQ2MTQ0LC0xNi40NjE0NGM5LjA5MTQsMCAxNi40NjE0NCw3LjM3MDA0IDE2LjQ2MTQ0LDE2LjQ2MTQ0YzAsOS4wOTE0MSAtNy4zNzAwMywxNi40NjE0NCAtMTYuNDYxNDQsMTYuNDYxNDRjLTkuMDkxNCwwIC0xNi40NjE0NCwtNy4zNzAwNCAtMTYuNDYxNDQsLTE2LjQ2MTQ0eiIgZmlsbD0iIzAwNzFmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg=="; - +"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NS41MzUiIGhlaWdodD0iNzEuNDk3IiB2aWV3Qm94PSIwIDAgNzUuNTM1IDcxLjQ5NyI+PGcgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIj48cGF0aCBkPSJNMjEuMzA3IDIxLjQ2MkMyMS4zMDcgMTIuMzcgMjguNjc3IDUgMzcuNzY4IDVzMTYuNDYxIDcuMzcgMTYuNDYxIDE2LjQ2Mi03LjM3IDE2LjQ2MS0xNi40NjEgMTYuNDYxLTE2LjQ2MS03LjM3LTE2LjQ2MS0xNi40NjF6IiBmaWxsPSJub25lIiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNNSA1MC4wMzZjMC05LjA5MSA3LjM3LTE2LjQ2MSAxNi40NjItMTYuNDYxczE2LjQ2MSA3LjM3IDE2LjQ2MSAxNi40NjFjMCA5LjA5Mi03LjM3IDE2LjQ2Mi0xNi40NjEgMTYuNDYyQzEyLjM3IDY2LjQ5OCA1IDU5LjEyOCA1IDUwLjAzNnoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik0zNy42MTMgNTAuMDM2YzAtOS4wOTEgNy4zNy0xNi40NjEgMTYuNDYxLTE2LjQ2MSA5LjA5MiAwIDE2LjQ2MiA3LjM3IDE2LjQ2MiAxNi40NjEgMCA5LjA5Mi03LjM3IDE2LjQ2Mi0xNi40NjIgMTYuNDYycy0xNi40NjEtNy4zNy0xNi40NjEtMTYuNDYyeiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjkwMGI0IiBzdHJva2Utd2lkdGg9IjEwIi8+PHBhdGggZD0iTTIxLjMwNyAyMS40NjJDMjEuMzA3IDEyLjM3IDI4LjY3NyA1IDM3Ljc2OCA1czE2LjQ2MSA3LjM3IDE2LjQ2MSAxNi40NjItNy4zNyAxNi40NjEtMTYuNDYxIDE2LjQ2MS0xNi40NjEtNy4zNy0xNi40NjEtMTYuNDYxIiBmaWxsPSJsaW1lIi8+PHBhdGggZD0iTTUgNTAuMDM2YzAtOS4wOTEgNy4zNy0xNi40NjEgMTYuNDYyLTE2LjQ2MXMxNi40NjEgNy4zNyAxNi40NjEgMTYuNDYxYzAgOS4wOTItNy4zNyAxNi40NjItMTYuNDYxIDE2LjQ2MkMxMi4zNyA2Ni40OTggNSA1OS4xMjggNSA1MC4wMzYiIGZpbGw9InJlZCIvPjxwYXRoIGQ9Ik0zNy42MTMgNTAuMDM2YzAtOS4wOTEgNy4zNy0xNi40NjEgMTYuNDYxLTE2LjQ2MSA5LjA5MiAwIDE2LjQ2MiA3LjM3IDE2LjQ2MiAxNi40NjEgMCA5LjA5Mi03LjM3IDE2LjQ2Mi0xNi40NjIgMTYuNDYycy0xNi40NjEtNy4zNy0xNi40NjEtMTYuNDYyIiBmaWxsPSJibHVlIi8+PC9nPjwvc3ZnPg=="; const effectIcon = -"data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI1Ny40NDI0MSIgaGVpZ2h0PSI3MC40NSIgdmlld0JveD0iMCwwLDU3LjQ0MjQxLDcwLjQ1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjEwLjI2NjQ1LC0xNDQuODU2NTUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGw9IiNmZmZmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiPjxwYXRoIGQ9Ik0yMTUuMjY2NDUsMTkzLjkwNDFjLTMuOTg4MTUsLTguMTE3MSAtMy45OTYxMSwtMTguMjQzMDUgMC4xNTIyMSwtMjYuNDExMDNjNC42ODc3OSwtOS41NzQzMSAxMi41NzY5MSwtMTMuODE3OTcgMTUuNzQ3NTYsLTE1LjE5Nzc1YzEuOTA1OCwtMC44ODUwOCAzLjkxMzg4LC0xLjU3NDk3IDYuMDc1MzcsLTIuMDgzMTNsMi4xMjA1OSwtMC40NTc2OGMxLjU1ODA1LC0wLjMxOTcgMy4xMDkyOCwwLjY0NjE0IDMuNDQ2OCwyLjE4NzQ1YzAuMzQwOTMsMS41NDQ2OCAtMC42NTExOCwzLjA2NTggLTIuMjE2MDUsMy40MDIzM2wtMi4wNjI2MywwLjQ0NDIyYy0xLjcxNDg4LDAuNDAzODQgLTMuMzU4MTYsMC45NjkyMSAtNC45NjA1MywxLjcxNjMxYy0yLjA4MzA4LDAuOTAxOSAtOC45NzMyOCw0LjM5MTczIC0xMi45NDg1MiwxMi41MTU2Yy0zLjAxNzIzLDUuOTMzMDUgLTMuOTE3MjksMTUuMzY2MDIgMC44MzE4NywyMy4xNDk5OGM0LjMwMjU0LDcuNDk3OTIgMTMuMTEyMTcsMTIuMDk0OTMgMjEuNDY4MzcsMTEuMzIwOTFjNy45MDI3NiwtMC41Njg3NCAxNS4xNTQzNCwtNS44Mjg3MiAxNy42OTc2OCwtMTIuNzk0OTJjMi41ODA4NCwtNi41NTIyNiAwLjg2NTk2LC0xMy4yNjk0MyAtMS45NjcxNywtMTcuMDUyMDRjLTMuNDEyNzEsLTQuNjYwOTYgLTcuNjYwNywtNi4wOTQ1OCAtOS4zMjc4NSwtNi40OTUwNWMtMC4yNDg4OCwtMC4wNzQwNCAtNi4wODU2LC0xLjgyNzM2IC0xMS4yNDA0NiwwLjc1MzgzYy0yLjIxOTQ1LDEuMDYzNDQgLTUuMDkwMDksMy40NTYxOCAtNi42Mjc2OCw3LjA1MDMzYy0xLjY2MDMzLDMuNzExOTQgLTEuMjMwNzYsOC40ODM5NSAxLjAxOTM4LDExLjY1NDA4YzIuMjYzNzgsMy4zOTg5NyA2LjUzMjIyLDUuMzIzOTIgMTAuMjA0MDQsNC42NzEwNWMzLjY1NDc3LC0wLjU3NTQ3IDYuMTI2NTEsLTMuMjk0NjQgNi43MTI5MSwtNS42ODQwMWMwLjY4ODY4LC0yLjU2NzczIC0wLjM2ODIsLTQuNzM4MzYgLTEuMTkzMjYsLTUuNTE5MTFjLTEuNDAxMjIsLTEuMzgzMTQgLTIuNjExNTIsLTEuNDA2NyAtMi42NjI2NiwtMS40MTAwN2MtMC41NzI3NiwtMC4wMTY4MyAtMC44NTU3MywwLjAyNjkyIC0xLjAyNjIsMC4wNTM4NGMtMC42NTQ1OSwwLjIzODk0IC0xLjU4MTkyLDAuNzYzOTMgLTEuODU0NjYsMS4zMTU4NGMtMC4wNDc3MywwLjA5MDg2IC0wLjE3MDQ3LDAuMzM5OSAwLjA2NDc4LDAuOTYyNDhjMC41NjI1MywxLjQ3NzM3IC0wLjE5Nzc0LDMuMTI5NzQgLTEuNjk0NDIsMy42ODUwMmMtMS40ODk4NiwwLjU1ODY0IC0zLjE2NzI0LC0wLjE5MTgyIC0zLjczMzE4LC0xLjY3MjU2Yy0wLjkzMDc0LC0yLjQ0OTk1IC0wLjQxNTkzLC00LjM2ODE4IDAuMTgwNjksLTUuNTQ2MDNjMS41NTgwNSwtMy4wNjU4IDUuMTc1MzIsLTQuMTc2MzUgNS41ODQ0MywtNC4yOTQxNGMwLjE4NzUxLC0wLjA1NzIxIDAuMzg1MjUsLTAuMDkwODYgMC41Nzk1OCwtMC4xMDc2OWMwLjM5ODg5LC0wLjA2MDU4IDEuMTAxMiwtMC4xNTQ4IDIuMDUyNCwtMC4xMTc3OWMyLjE3ODU0LDAuMDI2OTIgNC42NjA1MSwxLjE2NDQgNi41NjI5LDMuMDQ1NjFjMi4yNDY3MywyLjEyMDE1IDQuMDA1OTMsNi4zODA2MyAyLjc1ODEyLDExLjAxMTNjLTEuMjE3MTIsNC45NTcxIC01Ljg5NDY4LDkuMDU2MDYgLTExLjM1Mjk3LDkuOTE0MjFjLTUuODcwODIsMS4wNDY2MSAtMTIuNDgxNDUsLTEuODQ3NTYgLTE1Ljk3MjU3LC03LjA5NDA4Yy0zLjM2NDk4LC00LjcyODI2IC00LjAwOTM0LC0xMS42NDczNSAtMS41NDc4MiwtMTcuMTM2MTdjMi43MDAxNywtNi4zMjAwNiA3Ljg1ODQ0LC05LjE4MDU3IDkuMzcyMTcsLTkuOTA3NDhjNy4yNzg4NiwtMy42MzQ1NCAxNS4wNTg4OCwtMS4yMzUwNyAxNS4zODYxNywtMS4xMzQxMWMyLjA5MzMxLDAuNDk0NyA3LjkxMjk5LDIuNDQzMjIgMTIuNDM3MTMsOC42MjUyOWMzLjQ3NzQ5LDQuNjUwODYgNi4yOTY5OCwxMy4zMzY3MyAyLjcxMzgsMjIuNDI5ODFjLTMuMjcyOTMsOC45NjE4MyAtMTIuNTkwNTUsMTUuNzY5ODUgLTIyLjYzNzc2LDE2LjQ5MzM5Yy0wLjc4NzU1LDAuMDc0MDQgLTEuNTg1MzIsMC4xMTQ0MiAtMi4zNzk2OSwwLjExNDQyYy05Ljc1MDYsMCAtMTkuNjI3MzQsLTUuNjIwMDcgLTI0LjU4MTA2LC0xNC4yNDg3M2MwLDAgLTAuODIwNDksLTEuNDE4MzQgLTEuMTgxODEsLTIuMTUzNzN6IiBzdHJva2U9IiM2OTAwYjQiIHN0cm9rZS13aWR0aD0iMTAiLz48cGF0aCBkPSJNMjE2LjQ0ODI3LDE5Ni4wNTc4NGMtNS4xMzQ0MSwtOC40MjAwMSAtNS41NTM3NSwtMTkuNjU2NzkgLTEuMDI5NjEsLTI4LjU2NDc3YzQuNjg3NzksLTkuNTc0MzEgMTIuNTc2OTEsLTEzLjgxNzk3IDE1Ljc0NzU2LC0xNS4xOTc3NWMxLjkwNTgsLTAuODg1MDggMy45MTM4OCwtMS41NzQ5NyA2LjA3NTM3LC0yLjA4MzEzbDIuMTIwNTksLTAuNDU3NjhjMS41NTgwNSwtMC4zMTk3IDMuMTA5MjgsMC42NDYxNCAzLjQ0NjgsMi4xODc0NWMwLjM0MDkzLDEuNTQ0NjggLTAuNjUxMTgsMy4wNjU4IC0yLjIxNjA1LDMuNDAyMzNsLTIuMDYyNjMsMC40NDQyMmMtMS43MTQ4OCwwLjQwMzg0IC0zLjM1ODE2LDAuOTY5MjEgLTQuOTYwNTMsMS43MTYzMWMtMi4wODMwOCwwLjkwMTkgLTguOTczMjgsNC4zOTE3MyAtMTIuOTQ4NTIsMTIuNTE1NmMtMy4wMTcyMyw1LjkzMzA1IC0zLjkxNzI5LDE1LjM2NjAyIDAuODMxODcsMjMuMTQ5OThjNC4zMDI1NCw3LjQ5NzkyIDEzLjExMjE3LDEyLjA5NDkzIDIxLjQ2ODM3LDExLjMyMDkxYzcuOTAyNzYsLTAuNTY4NzQgMTUuMTU0MzQsLTUuODI4NzIgMTcuNjk3NjgsLTEyLjc5NDkyYzIuNTgwODQsLTYuNTUyMjYgMC44NjU5NiwtMTMuMjY5NDMgLTEuOTY3MTcsLTE3LjA1MjA0Yy0zLjQxMjcxLC00LjY2MDk2IC03LjY2MDcsLTYuMDk0NTggLTkuMzI3ODUsLTYuNDk1MDVjLTAuMjQ4ODgsLTAuMDc0MDQgLTYuMDg1NiwtMS44MjczNiAtMTEuMjQwNDYsMC43NTM4M2MtMi4yMTk0NSwxLjA2MzQ0IC01LjA5MDA5LDMuNDU2MTggLTYuNjI3NjgsNy4wNTAzM2MtMS42NjAzMywzLjcxMTk0IC0xLjIzMDc2LDguNDgzOTUgMS4wMTkzOCwxMS42NTQwOGMyLjI2Mzc4LDMuMzk4OTcgNi41MzIyMiw1LjMyMzkyIDEwLjIwNDA0LDQuNjcxMDVjMy42NTQ3NywtMC41NzU0NyA2LjEyNjUxLC0zLjI5NDY0IDYuNzEyOTEsLTUuNjg0MDFjMC42ODg2OCwtMi41Njc3MyAtMC4zNjgyLC00LjczODM2IC0xLjE5MzI2LC01LjUxOTExYy0xLjQwMTIyLC0xLjM4MzE0IC0yLjYxMTUyLC0xLjQwNjcgLTIuNjYyNjYsLTEuNDEwMDdjLTAuNTcyNzYsLTAuMDE2ODMgLTAuODU1NzMsMC4wMjY5MiAtMS4wMjYyLDAuMDUzODRjLTAuNjU0NTksMC4yMzg5NCAtMS41ODE5MiwwLjc2MzkzIC0xLjg1NDY2LDEuMzE1ODRjLTAuMDQ3NzMsMC4wOTA4NiAtMC4xNzA0NywwLjMzOTkgMC4wNjQ3OCwwLjk2MjQ4YzAuNTYyNTMsMS40NzczNyAtMC4xOTc3NCwzLjEyOTc0IC0xLjY5NDQyLDMuNjg1MDJjLTEuNDg5ODYsMC41NTg2NCAtMy4xNjcyNCwtMC4xOTE4MiAtMy43MzMxOCwtMS42NzI1NmMtMC45MzA3NCwtMi40NDk5NSAtMC40MTU5MywtNC4zNjgxOCAwLjE4MDY5LC01LjU0NjAzYzEuNTU4MDUsLTMuMDY1OCA1LjE3NTMyLC00LjE3NjM1IDUuNTg0NDMsLTQuMjk0MTRjMC4xODc1MSwtMC4wNTcyMSAwLjM4NTI1LC0wLjA5MDg2IDAuNTc5NTgsLTAuMTA3NjljMC4zOTg4OSwtMC4wNjA1OCAxLjEwMTIsLTAuMTU0OCAyLjA1MjQsLTAuMTE3NzljMi4xNzg1NCwwLjAyNjkyIDQuNjYwNTEsMS4xNjQ0IDYuNTYyOSwzLjA0NTYxYzIuMjQ2NzMsMi4xMjAxNSA0LjAwNTkzLDYuMzgwNjMgMi43NTgxMiwxMS4wMTEzYy0xLjIxNzEyLDQuOTU3MSAtNS44OTQ2OCw5LjA1NjA2IC0xMS4zNTI5Nyw5LjkxNDIxYy01Ljg3MDgyLDEuMDQ2NjEgLTEyLjQ4MTQ1LC0xLjg0NzU2IC0xNS45NzI1NywtNy4wOTQwOGMtMy4zNjQ5OCwtNC43MjgyNiAtNC4wMDkzNCwtMTEuNjQ3MzUgLTEuNTQ3ODIsLTE3LjEzNjE3YzIuNzAwMTcsLTYuMzIwMDYgNy44NTg0NCwtOS4xODA1NyA5LjM3MjE3LC05LjkwNzQ4YzcuMjc4ODYsLTMuNjM0NTQgMTUuMDU4ODgsLTEuMjM1MDcgMTUuMzg2MTcsLTEuMTM0MTFjMi4wOTMzMSwwLjQ5NDcgNy45MTI5OSwyLjQ0MzIyIDEyLjQzNzEzLDguNjI1MjljMy40Nzc0OSw0LjY1MDg2IDYuMjk2OTgsMTMuMzM2NzMgMi43MTM4LDIyLjQyOTgxYy0zLjI3MjkzLDguOTYxODMgLTEyLjU5MDU1LDE1Ljc2OTg1IC0yMi42Mzc3NiwxNi40OTMzOWMtMC43ODc1NSwwLjA3NDA0IC0xLjU4NTMyLDAuMTE0NDIgLTIuMzc5NjksMC4xMTQ0MmMtOS43NTA2LDAgLTE5LjYyNzM0LC01LjYyMDA3IC0yNC41ODEwNiwtMTQuMjQ4NzN6IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L2c+PC9zdmc+"; +"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1Ny40NDIiIGhlaWdodD0iNzAuNDUiIHZpZXdCb3g9IjAgMCA1Ny40NDIgNzAuNDUiPjxnIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIj48cGF0aCBkPSJNNSA0OS4wNDdjLTMuOTg4LTguMTE3LTMuOTk2LTE4LjI0My4xNTMtMjYuNDFDOS44NCAxMy4wNjIgMTcuNzMgOC44MTggMjAuOSA3LjQzOGEzMS40IDMxLjQgMCAwIDEgNi4wNzYtMi4wODNsMi4xMi0uNDU3YzEuNTU4LS4zMiAzLjExLjY0NiAzLjQ0NyAyLjE4Ny4zNCAxLjU0NS0uNjUxIDMuMDY2LTIuMjE2IDMuNDAybC0yLjA2My40NDVhMjUuNCAyNS40IDAgMCAwLTQuOTYgMS43MTZjLTIuMDgzLjkwMi04Ljk3NCA0LjM5Mi0xMi45NDkgMTIuNTE1LTMuMDE3IDUuOTMzLTMuOTE3IDE1LjM2Ni44MzIgMjMuMTUgNC4zMDMgNy40OTggMTMuMTEyIDEyLjA5NSAyMS40NjggMTEuMzIxIDcuOTAzLS41NjggMTUuMTU1LTUuODI4IDE3LjY5OC0xMi43OTUgMi41ODEtNi41NTIuODY2LTEzLjI2OS0xLjk2Ny0xNy4wNTItMy40MTMtNC42Ni03LjY2LTYuMDk0LTkuMzI4LTYuNDk1LS4yNDktLjA3NC02LjA4NS0xLjgyNy0xMS4yNC43NTQtMi4yMiAxLjA2NC01LjA5IDMuNDU2LTYuNjI4IDcuMDUtMS42NiAzLjcxMi0xLjIzIDguNDg0IDEuMDIgMTEuNjU1IDIuMjYzIDMuMzk5IDYuNTMyIDUuMzIzIDEwLjIwMyA0LjY3IDMuNjU1LS41NzUgNi4xMjctMy4yOTQgNi43MTMtNS42ODMuNjg5LTIuNTY4LS4zNjgtNC43MzktMS4xOTMtNS41Mi0xLjQwMS0xLjM4My0yLjYxMS0xLjQwNi0yLjY2My0xLjQxYTUgNSAwIDAgMC0xLjAyNi4wNTRjLS42NTQuMjQtMS41ODIuNzY0LTEuODU0IDEuMzE2LS4wNDguMDktLjE3LjM0LjA2NC45NjMuNTYzIDEuNDc3LS4xOTcgMy4xMy0xLjY5NCAzLjY4NS0xLjQ5LjU1OC0zLjE2Ny0uMTkyLTMuNzMzLTEuNjczLS45MzEtMi40NS0uNDE2LTQuMzY4LjE4LTUuNTQ2IDEuNTU4LTMuMDY2IDUuMTc2LTQuMTc2IDUuNTg1LTQuMjk0LjE4Ny0uMDU3LjM4NS0uMDkxLjU4LS4xMDguMzk4LS4wNiAxLjEtLjE1NSAyLjA1Mi0uMTE4IDIuMTc4LjAyNyA0LjY2IDEuMTY1IDYuNTYzIDMuMDQ2IDIuMjQ2IDIuMTIgNC4wMDYgNi4zOCAyLjc1OCAxMS4wMTEtMS4yMTcgNC45NTctNS44OTUgOS4wNTYtMTEuMzUzIDkuOTE0LTUuODcgMS4wNDctMTIuNDgyLTEuODQ3LTE1Ljk3My03LjA5NC0zLjM2NS00LjcyOC00LjAwOS0xMS42NDctMS41NDgtMTcuMTM2IDIuNy02LjMyIDcuODU5LTkuMTggOS4zNzMtOS45MDcgNy4yNzktMy42MzUgMTUuMDU5LTEuMjM1IDE1LjM4Ni0xLjEzNCAyLjA5My40OTQgNy45MTMgMi40NDMgMTIuNDM3IDguNjI1IDMuNDc3IDQuNjUgNi4yOTcgMTMuMzM3IDIuNzE0IDIyLjQzLTMuMjczIDguOTYyLTEyLjU5IDE1Ljc3LTIyLjYzOCAxNi40OTMtLjc4OC4wNzQtMS41ODUuMTE1LTIuMzguMTE1LTkuNzUgMC0xOS42MjctNS42Mi0yNC41OC0xNC4yNSAwIDAtLjgyMS0xLjQxOC0xLjE4My0yLjE1M3oiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik02LjE4MiA1MS4yMDFjLTUuMTM0LTguNDItNS41NTMtMTkuNjU3LTEuMDMtMjguNTY1QzkuODQgMTMuMDYyIDE3LjczIDguODE4IDIwLjkgNy40MzhhMzEuNCAzMS40IDAgMCAxIDYuMDc2LTIuMDgzbDIuMTItLjQ1N2MxLjU1OC0uMzIgMy4xMS42NDYgMy40NDcgMi4xODcuMzQgMS41NDUtLjY1MSAzLjA2Ni0yLjIxNiAzLjQwMmwtMi4wNjMuNDQ1YTI1LjQgMjUuNCAwIDAgMC00Ljk2IDEuNzE2Yy0yLjA4My45MDItOC45NzQgNC4zOTItMTIuOTQ5IDEyLjUxNS0zLjAxNyA1LjkzMy0zLjkxNyAxNS4zNjYuODMyIDIzLjE1IDQuMzAzIDcuNDk4IDEzLjExMiAxMi4wOTUgMjEuNDY4IDExLjMyMSA3LjkwMy0uNTY4IDE1LjE1NS01LjgyOCAxNy42OTgtMTIuNzk1IDIuNTgxLTYuNTUyLjg2Ni0xMy4yNjktMS45NjctMTcuMDUyLTMuNDEzLTQuNjYtNy42Ni02LjA5NC05LjMyOC02LjQ5NS0uMjQ5LS4wNzQtNi4wODUtMS44MjctMTEuMjQuNzU0LTIuMjIgMS4wNjQtNS4wOSAzLjQ1Ni02LjYyOCA3LjA1LTEuNjYgMy43MTItMS4yMyA4LjQ4NCAxLjAyIDExLjY1NSAyLjI2MyAzLjM5OSA2LjUzMiA1LjMyMyAxMC4yMDMgNC42NyAzLjY1NS0uNTc1IDYuMTI3LTMuMjk0IDYuNzEzLTUuNjgzLjY4OS0yLjU2OC0uMzY4LTQuNzM5LTEuMTkzLTUuNTItMS40MDEtMS4zODMtMi42MTEtMS40MDYtMi42NjMtMS40MWE1IDUgMCAwIDAtMS4wMjYuMDU0Yy0uNjU0LjI0LTEuNTgyLjc2NC0xLjg1NCAxLjMxNi0uMDQ4LjA5LS4xNy4zNC4wNjQuOTYzLjU2MyAxLjQ3Ny0uMTk3IDMuMTMtMS42OTQgMy42ODUtMS40OS41NTgtMy4xNjctLjE5Mi0zLjczMy0xLjY3My0uOTMxLTIuNDUtLjQxNi00LjM2OC4xOC01LjU0NiAxLjU1OC0zLjA2NiA1LjE3Ni00LjE3NiA1LjU4NS00LjI5NC4xODctLjA1Ny4zODUtLjA5MS41OC0uMTA4LjM5OC0uMDYgMS4xLS4xNTUgMi4wNTItLjExOCAyLjE3OC4wMjcgNC42NiAxLjE2NSA2LjU2MyAzLjA0NiAyLjI0NiAyLjEyIDQuMDA2IDYuMzggMi43NTggMTEuMDExLTEuMjE3IDQuOTU3LTUuODk1IDkuMDU2LTExLjM1MyA5LjkxNC01Ljg3IDEuMDQ3LTEyLjQ4Mi0xLjg0Ny0xNS45NzMtNy4wOTQtMy4zNjUtNC43MjgtNC4wMDktMTEuNjQ3LTEuNTQ4LTE3LjEzNiAyLjctNi4zMiA3Ljg1OS05LjE4IDkuMzczLTkuOTA3IDcuMjc5LTMuNjM1IDE1LjA1OS0xLjIzNSAxNS4zODYtMS4xMzQgMi4wOTMuNDk0IDcuOTEzIDIuNDQzIDEyLjQzNyA4LjYyNSAzLjQ3NyA0LjY1IDYuMjk3IDEzLjMzNyAyLjcxNCAyMi40My0zLjI3MyA4Ljk2Mi0xMi41OSAxNS43Ny0yMi42MzggMTYuNDkzLS43ODguMDc0LTEuNTg1LjExNS0yLjM4LjExNS05Ljc1IDAtMTkuNjI3LTUuNjItMjQuNTgtMTQuMjUiLz48L2c+PC9zdmc+"; let newColorType = ""; - let overlayImageContainer = ""; + let laidImgContain = ""; const vm = Scratch.vm; const fontMenu = [ - "Scratch", "Sans Serif", "Serif", - "Handwriting", "Marker", "Curly", "Pixel" - ]; + "Sans Serif", "Serif", "Handwriting", + "Marker", "Curly", "Pixel", "Scratch" + ]; const xmlEscape = function (unsafe) { return Scratch.Cast.toString(unsafe).replace(/[<>&'"]/g, c => { @@ -59,12 +56,8 @@ this.sliderInfo = [0, 100, 50]; this.Timeout = 0; - this.shadowEnabled = true; - this.isInputEnabled = "Enabled"; - this.DropdownText = "Dropdown"; - this.fontSize = "14px"; - this.textAlign = "left"; - this.fontFamily = "Sans Serif"; + this.inputType = "Enabled"; + this.fontSize = "14px"; this.fontFamily = "Sans Serif"; this.textAlign = "left"; // overlay + Image, input, dropdown button this.mainUIinfo = { // Border Radius @@ -89,6 +82,7 @@ inputOutline: ["", 0], dropBtnOutline: ["", 0] }; + this.DropdownText = "Dropdown"; this.lastPressBtn = ""; this.buttonJSON = { "Submit": { @@ -105,11 +99,9 @@ }, }; - this.questionColor = "#000000"; - this.inputColor = "#000000"; - this.textBoxColor = ["#ffffff"]; - this.inputFieldColor = "#ffffff"; - this.dropdownButtonColor = ["#5f5f5f", "#ffffff"]; + this.questionColor = "#000000"; this.inputColor = "#000000"; + this.textBoxColor = ["#ffffff"]; this.inputFieldColor = "#a5aec3"; + this.dropdwnBtnColor = ["#5f5f5f", "#ffffff"]; this.overlayImage = [" ", " ", " "]; this.Blur = 0; this.Brightness = 0; this.Opacity = 100; @@ -117,6 +109,7 @@ this.Sepia = 0; this.Contrast = 100; this.Scale = 100; this.SkewX = 0; this.SkewY = 0; this.Rotation = 90; this.imgScale = [100, 100, 100]; + this.shadowEnabled = true; this.shadowS = [0, 0, 5, "#000000"]; } @@ -167,22 +160,6 @@ text: "reset user input" }, { blockType: Scratch.BlockType.LABEL, text: "Formatting" }, - { - opcode: "setEnable", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: true, text: "set [ENABLE_MENU] to be [ACTION]", - arguments: { - ENABLE_MENU: { type: Scratch.ArgumentType.STRING, menu: "enableMenu" }, - ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } - }, - }, - { - opcode: "getBoxCount", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, text: "box count" - }, - { - opcode: "getMaxCount", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: true, text: "box limit" - }, { opcode: "setFontSize", blockType: Scratch.BlockType.COMMAND, @@ -210,33 +187,11 @@ FONT: { type: Scratch.ArgumentType.STRING, menu: "fontMenu" } }, }, - { - opcode: "setDropShadow", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] shadow to x [x] y [y] z [z] color [COLOR]", - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, - x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, - z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 2 }, - COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" } - }, - }, - { - opcode: "setOutline", - blockType: Scratch.BlockType.COMMAND, - text: "set [ELEMENT] outline to [COLOR] thickness [THICK]", - arguments: { - ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, - COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000" }, - THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } - }, - }, "---", { opcode: "setInputType", blockType: Scratch.BlockType.COMMAND, - text: "set Input Box to be [ACTION]", + text: "set input type to [ACTION]", blockIconURI: formatIcon, arguments: { ACTION: { type: Scratch.ArgumentType.STRING, menu: "inputActionMenu" } @@ -360,27 +315,7 @@ blockIconURI: colorIcon, arguments: { COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "colorSettingsMenu" }, - COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#000000" } - }, - }, - { - opcode: "setGradient", blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to gradient with [COLOR1] and [COLOR2] with direction [DIR]", - hideFromPalette: true, //deprecated but needed for support - arguments: { - COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, - DIR: { type: Scratch.ArgumentType.ANGLE } - }, - }, - { - opcode: "setCircleGradient", blockType: Scratch.BlockType.COMMAND, - text: "set [COLOR_TYPE] color to radial gradient with [COLOR1] and [COLOR2] at x [X] y [Y]", - hideFromPalette: true, //deprecated but needed for support - arguments: { - COLOR_TYPE: { type: Scratch.ArgumentType.STRING, menu: "elementMenu" }, - COLOR1: { type: Scratch.ArgumentType.COLOR }, COLOR2: { type: Scratch.ArgumentType.COLOR }, - X: { type: Scratch.ArgumentType.NUMBER }, Y: { type: Scratch.ArgumentType.NUMBER } + COLOR: { type: Scratch.ArgumentType.COLOR } }, }, "---", @@ -408,7 +343,7 @@ { opcode: "enableShadow", blockType: Scratch.BlockType.COMMAND, - text: "set box shadow to be [ACTION]", + text: "set box shadow to [ACTION]", blockIconURI: colorIcon, arguments: { ACTION: { type: Scratch.ArgumentType.STRING, menu: "buttonActionMenu" } @@ -424,6 +359,30 @@ AMT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } }, }, + { + opcode: "setDropShadow", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] shadow to x [x] y [y] z [z] color [COLOR]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, + x: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0 }, + z: { type: Scratch.ArgumentType.NUMBER, defaultValue: 2 }, + COLOR: { type: Scratch.ArgumentType.COLOR } + }, + }, + { + opcode: "setOutline", + blockType: Scratch.BlockType.COMMAND, + text: "set [ELEMENT] outline to [COLOR] thickness [THICK]", + blockIconURI: colorIcon, + arguments: { + ELEMENT: { type: Scratch.ArgumentType.STRING, menu: "textsMenu" }, + COLOR: { type: Scratch.ArgumentType.COLOR }, + THICK: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 } + }, + }, "---", { opcode: "setBorder", @@ -447,6 +406,7 @@ VALUE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5 }, }, }, + "---", { opcode: "setPadding", blockType: Scratch.BlockType.COMMAND, @@ -587,11 +547,9 @@ arguments: { INFO: { type: Scratch.ArgumentType.STRING, menu: "boxInfo" } }, - }, + } ], menus: { - enableMenu: { acceptReporters: true, items: ["Button 2", "Button 3", "Button 4", "Textbox Shadow"] }, - // ^ Old Menu ^ (Needed for V2 Support) fontMenu: { acceptReporters: true, items: "allFonts" }, buttonMenu: { acceptReporters: true, @@ -626,16 +584,15 @@ acceptReporters: true, items: [ "None", "Text", "Password", "Number", "Color", - "Dropdown", "Multi-Select Dropdown", + "Dropdown", "Single Dropdown", "Multi-Select Dropdown", "Horizontal Slider", "Vertical Slider" ], }, effectMenu: { acceptReporters: true, items: [ - "Blur", "Brightness", "Opacity", - "Invert", "Saturation", "Hue", - "Sepia", "Contrast", + "Blur", "Brightness", "Opacity", "Invert", + "Saturation", "Hue", "Sepia", "Contrast", "Scale", "SkewX", "SkewY", ], }, @@ -655,12 +612,8 @@ } allFonts() { - const customFonts = Scratch.vm.runtime.fontManager - ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({ - text: i.name, value: i.family - })) - : []; - return [ ...fontMenu, ...customFonts ]; + const custFonts = vm.runtime.fontManager ? vm.runtime.fontManager.getFonts().map((i) => ({ text: i.name, value: i.family })) : []; + return [ ...fontMenu, ...custFonts ]; } allButtons(array, enableTxt, justTxt) { @@ -713,9 +666,9 @@ overlay.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; overlay.style.width = this.mainUIinfo.dimensions[0]; overlay.style.height = this.mainUIinfo.dimensions[1]; - overlayImageContainer.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; - overlayImageContainer.style.background = ""; - this.setImageStyles(overlayImageContainer, this.overlayImage[0], this.imgScale[0]); + laidImgContain.style.borderRadius = `${this.mainUIinfo.overlayRad}px`; + laidImgContain.style.background = ""; + this.setImageStyles(laidImgContain, this.overlayImage[0], this.imgScale[0]); this.updateButtonImages(overlay); } updateButtonImages(overlay) { @@ -725,13 +678,14 @@ text.style.textShadow = this.mainUIinfo.overlayTxtShad; this.tryOutline(text, this.mainUIinfo.overlayOutline[0], this.mainUIinfo.overlayOutline[1]); } - const inputField = overlay.querySelector("input"); + const inputField = overlay.querySelector(this.inputType.includes("Single") ? "select" : "input"); if (inputField) { - inputField.style.width = this.isInputEnabled === "Color" ? "100%" : "auto"; + inputField.style.width = this.inputType === "Color" || this.inputType.includes("Single") ? "100%" : + this.inputType === "Horizontal Slider" ? "95%" : "auto"; inputField.style.background = ""; inputField.style.fontFamily = this.fontFamily; inputField.style[this.inputFieldColor.includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.inputFieldColor; - inputField.style.color = this.inputColor; + inputField.style.color = this.inputColor; inputField.style.accentColor = this.inputFieldColor; inputField.style.textShadow = this.mainUIinfo.inputTxtShad; this.tryOutline(inputField, this.mainUIinfo.inputOutline[0], this.mainUIinfo.inputOutline[1]); inputField.style.border = this.mainUIinfo.inputBord; @@ -744,18 +698,18 @@ if (dropBtn) { dropBtn.style.backgroundImage = ""; dropBtn.style.fontFamily = this.fontFamily; - dropBtn.style.color = this.dropdownButtonColor[1]; + dropBtn.style.color = this.dropdwnBtnColor[1]; dropBtn.style.borderRadius = `${this.mainUIinfo.dropBtnRad}px`; dropBtn.style.border = this.mainUIinfo.dropBtnBord; dropBtn.style.padding = this.mainUIinfo.dropBtnPad; dropBtn.style.textShadow = this.mainUIinfo.dropBtnTxtShad; this.tryOutline(dropBtn, this.mainUIinfo.dropBtnOutline[0], this.mainUIinfo.dropBtnOutline[1]); - dropBtn.style[this.dropdownButtonColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdownButtonColor[0]; + dropBtn.style[this.dropdwnBtnColor[0].includes("gradient") ? "backgroundImage" : "backgroundColor"] = this.dropdwnBtnColor[0]; this.setImageStyles(dropBtn, this.overlayImage[2], this.imgScale[2]); } - const buttonContainer = overlay.querySelector(".button-container"); - if (buttonContainer) { - const buttons = buttonContainer.querySelectorAll("button"); + const btnContain = overlay.querySelector(".button-container"); + if (btnContain) { + const buttons = btnContain.querySelectorAll("button"); buttons.forEach((button, index) => { const buttonName = Object.keys(this.buttonJSON)[index]; const buttonInfo = this.buttonJSON[buttonName]; @@ -790,7 +744,7 @@ if (canFetch) { element.style.background = `url(${encodeURI(url)})`; element.style.backgroundSize = `${scale}%`; - } else { console.log("Cannot fetch content from the URL") } + } else { console.warn("Cannot fetch content from the URL") } }); } } @@ -824,14 +778,13 @@ "Textbox": () => { this.textBoxColor[0] = colorValue; this.overlayImage[0] = " "; }, "Textbox Shadow": () => { this.shadowS[3] = colorValue }, "Input Box": () => { this.inputFieldColor = colorValue; this.overlayImage[1] = " "; }, - "Dropdown Button": () => { this.dropdownButtonColor[0] = colorValue; this.overlayImage[2] = " "; }, - "Dropdown Text": () => this.dropdownButtonColor[1] = colorValue, + "Dropdown Button": () => { this.dropdwnBtnColor[0] = colorValue; this.overlayImage[2] = " "; }, + "Dropdown Text": () => this.dropdwnBtnColor[1] = colorValue, }; const buttonInfo = this.buttonJSON[colorType] || this.buttonJSON[colorType.replace(" Text", "")]; if (buttonInfo) { - if (colorType.includes(" Text")) { - buttonInfo.textColor = colorValue; - } else { + if (colorType.includes(" Text")) buttonInfo.textColor = colorValue; + else { buttonInfo.color = colorValue; buttonInfo.image = " "; } @@ -844,7 +797,7 @@ findGradientType(menu) { const colorTypeMap = { Textbox: { newColorType: "textBoxColor", ind: 0 }, - "Dropdown Button": { newColorType: "dropdownButtonColor", ind: 2 } + "Dropdown Button": { newColorType: "dropdwnBtnColor", ind: 2 } }; if (colorTypeMap[menu]) { const { newColorType, ind } = colorTypeMap[menu]; @@ -854,23 +807,6 @@ return menu; } - setGradient(args) { - if (args.COLOR_TYPE === "Input Box") throw new Error ("As of Better Input V4, this Option no Longer Works"); - const newColorType = this.findGradientType(args.COLOR_TYPE); - const gradientColor = `linear-gradient(${args.DIR - 90}deg, ${args.COLOR2}, ${args.COLOR1})`; - if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; - else this.buttonJSON[newColorType[1]].color = gradientColor; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - setCircleGradient(args) { - const newColorType = this.findGradientType(args.COLOR_TYPE); - const newPos = [args.X + 50, args.Y + 50]; - const gradientColor = `radial-gradient(circle at ${newPos[0]}% ${newPos[1]}%, ${args.COLOR2}, ${args.COLOR1})`; - if (newColorType[0] !== "button") this[newColorType][0] = gradientColor; - else this.buttonJSON[newColorType[1]].color = gradientColor; - this.activeOverlays.forEach((overlay) => { this.updateOverlay(overlay) }); - } - callStyling(element, value, type, elements) { const elementID = elements[element]; if (elementID !== undefined) this.mainUIinfo[elementID] = value; @@ -908,8 +844,7 @@ setDropShadow(args) { const casted = [ - Scratch.Cast.toNumber(args.x), Scratch.Cast.toNumber(args.y), - Scratch.Cast.toNumber(args.z), + Scratch.Cast.toNumber(args.x), Scratch.Cast.toNumber(args.y), Scratch.Cast.toNumber(args.z) ]; let shadow = args.z === 0 ? "none" : `${casted[0]}px ${casted[1] * -1}px ${casted[2]}px ${args.COLOR}`; this.callStyling( @@ -1004,9 +939,8 @@ setSlider(args) { this.sliderInfo = [args.MIN, args.MAX, args.DEFAULT] } setInputType(args) { - if (args.ACTION === "Text" || args.ACTION === "None") { - this.isInputEnabled = args.ACTION === "Text" ? "Enabled" : "Disabled"; - } else { this.isInputEnabled = args.ACTION } + if (args.ACTION === "Text" || args.ACTION === "None") this.inputType = args.ACTION === "Text" ? "Enabled" : "Disabled"; + else this.inputType = args.ACTION; } enableShadow(args) { this.shadowEnabled = args.ACTION === "Enabled" } @@ -1014,29 +948,25 @@ setButtonText(args) { const buttonMenu = args.BUTTON_MENU; const text = args.TEXT; - if (buttonMenu === "Dropdown") { - this.DropdownText = text; - } else if (this.buttonJSON[buttonMenu]) { + if (buttonMenu === "Dropdown") this.DropdownText = text; + else if (this.buttonJSON[buttonMenu]) { this.buttonJSON[buttonMenu].name = text; - Scratch.vm.extensionManager.refreshBlocks(); + vm.extensionManager.refreshBlocks(); } } setDropdown(args) { try { this.optionList = JSON.parse(args.DROPDOWN); - } catch { this.optionList = ["Undefined Array Error"] } + } catch { this.optionList = ["Invalid Array"] } } removeAskBoxes() { const overlaysToRemove = []; this.activeOverlays.forEach((overlay) => { if (overlay) { - if (this.appendTarget[0] === "window" && overlay.parentNode) { - overlay.parentNode.removeChild(overlay); - } else if (overlay.parentNode.parentNode !== document.documentElement) { - overlay.parentNode.parentNode.removeChild(overlay.parentNode); - } + if (this.appendTarget[0] === "window" && overlay.parentNode) overlay.parentNode.removeChild(overlay); + else if (overlay.parentNode.parentNode !== document.documentElement) overlay.parentNode.parentNode.removeChild(overlay.parentNode); overlaysToRemove.push(overlay); } if (this.askBoxPromises) { @@ -1050,7 +980,7 @@ this.askBoxInfo[0] = 0; this.isDropdownOpen = false; // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info - const bugged = document.querySelectorAll(`[class^="SP-ask-box"]`); + const bugged = document.querySelectorAll(`div[class^="SP-ask-box"]`); bugged.forEach((box) => { box.parentNode.removeChild(box) }); } @@ -1070,7 +1000,7 @@ this.isWaitingForInput = true; this.lastPressBtn = ""; this.askBoxInfo[0]++; - let selectedOptions = []; + let selectOpts = []; return new Promise((resolve) => { const askBoxPromise = { resolve }; this.askBoxPromises.push(askBoxPromise); @@ -1078,7 +1008,6 @@ overlay.classList.add("SP-ask-box"); overlay.style.pointerEvents = "auto"; overlay.style.position = "fixed"; - overlay.style.zIndex = "9999"; overlay.style.fontSize = this.fontSize; overlay.style.left = this.appendTarget[0] === "window" ? `${50 + this.textBoxX}%` : "0%"; overlay.style.top = this.appendTarget[0] === "window" ? `${50 + this.textBoxY}%` : "0%"; @@ -1090,13 +1019,13 @@ focusBG.style.left = this.appendTarget[0] === "window" ? "0%" : "-50%"; focusBG.style.top = this.appendTarget[0] === "window" ? "0%" : "-50%"; - overlayImageContainer = document.createElement("div"); - overlayImageContainer.style.width = "100%"; - overlayImageContainer.style.height = "100%"; - overlayImageContainer.style.position = "absolute"; - overlayImageContainer.style.top = 0; - overlayImageContainer.style.left = 0; - overlayImageContainer.style.zIndex = "-1"; + laidImgContain = document.createElement("div"); + laidImgContain.style.width = "100%"; + laidImgContain.style.height = "100%"; + laidImgContain.style.position = "absolute"; + laidImgContain.style.top = 0; + laidImgContain.style.left = 0; + laidImgContain.style.zIndex = "-1"; if (this.forceInput !== "Disabled") { const overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; const handleKeydown = (event) => { @@ -1132,10 +1061,10 @@ questionText.innerHTML = xmlEscape(question).replace(/\n/g, "
"); const inputField = document.createElement("input"); - inputField.style.display = this.isInputEnabled ? "block" : "none"; + inputField.style.display = this.inputType ? "block" : "none"; inputField.style.fontSize = this.fontSize; inputField.style.margin = "0 auto"; - inputField.type = this.isInputEnabled.toLowerCase(); + inputField.type = this.inputType.toLowerCase(); inputField.addEventListener("input", () => { if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; else { @@ -1144,64 +1073,47 @@ this.userInput = newInput; } }); - const buttonContainer = document.createElement("div"); - buttonContainer.classList.add("button-container"); + const btnContain = document.createElement("div"); + btnContain.classList.add("button-container"); for (const buttonName in this.buttonJSON) { - const buttonInfo = this.buttonJSON[buttonName]; - if (buttonInfo.name.includes("")) { - const lineBreak = document.createElement("br"); - buttonContainer.appendChild(lineBreak); - } else { - const button = document.createElement("button"); - if (this.uiOrder[0] !== "buttons") button.style.marginTop = "10px"; - if (this.uiOrder[2] !== "buttons") button.style.marginBottom = "10px"; - button.style.marginRight = "5px"; - button.style.cursor = "pointer"; - button.innerHTML = xmlEscape(buttonInfo.name).replace(/\n/g, "
"); - button.style.display = "inline-block"; - button.addEventListener("click", () => { - this.lastPressBtn = buttonInfo.name; - if (this.askBoxInfo[1] == 1) this.userInput = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; + const btnInfo = this.buttonJSON[buttonName]; + if (btnInfo.name.includes("")) btnContain.appendChild(document.createElement("br")); + else { + const btn = document.createElement("button"); + if (this.uiOrder[0] !== "buttons") btn.style.marginTop = "10px"; + if (this.uiOrder[2] !== "buttons") btn.style.marginBottom = "10px"; + btn.style.marginRight = "5px"; + btn.style.cursor = "pointer"; + btn.innerHTML = xmlEscape(btnInfo.name).replace(/\n/g, "
"); + btn.style.display = "inline-block"; + btn.addEventListener("click", () => { + this.lastPressBtn = btnInfo.name; + if (this.askBoxInfo[1] == 1) this.userInput = this.inputType === "Disabled" ? btnInfo.name : inputField.value; else { const newInput = [...this.userInput]; - newInput[index] = this.isInputEnabled === "Disabled" ? buttonInfo.name : inputField.value; + newInput[index] = this.inputType === "Disabled" ? btnInfo.name : inputField.value; this.userInput = newInput; } this.closeOverlay(overlay, hasDecreased); hasDecreased = true; resolve(); }); - buttonContainer.appendChild(button); + btnContain.appendChild(btn); } } const dropdown = document.createElement("div"); dropdown.className = "dropdown"; - const dropdownButton = document.createElement("button"); - dropdownButton.className = "dropbtn"; - dropdownButton.innerHTML = xmlEscape(this.DropdownText).replace(/\n/g, "
"); - const dropdownContent = document.createElement("div"); - dropdownContent.id = "myDropdown"; - dropdownContent.className = "dropdown-content"; - dropdownContent.style.display = "none"; - - const optionLabels = this.optionList; - optionLabels.forEach((label, index) => { - const optionLabel = document.createElement("label"); - optionLabel.style.color = this.questionColor; - optionLabel.textContent = ""; - const optionRadio = document.createElement("input"); - optionRadio.type = this.isInputEnabled === "Dropdown" ? "radio" : "checkbox"; - optionRadio.name = "dropdownOptions"; - optionRadio.value = index; - optionRadio.classList.add("dropdown-radio"); - optionRadio.addEventListener("click", () => { - if (this.isInputEnabled === "Multi-Select Dropdown") { - if (selectedOptions.includes(label)) { - selectedOptions = selectedOptions.filter(item => item !== label); - } else { selectedOptions.push(label) } - inputField.value = selectedOptions.length > 0 ? JSON.stringify(selectedOptions) : ""; - } else { inputField.value = label } + let dropdwnBtn, dropdwnCont; + if (this.inputType === "Single Dropdown") { + dropdwnBtn = document.createElement("select"); + this.optionList.forEach((label) => { + let opt = document.createElement("option"); + opt.value = label; opt.text = label; + dropdwnBtn.appendChild(opt); + }); + dropdwnBtn.addEventListener("input", () => { + inputField.value = dropdwnBtn.value; if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; else { const newInput = [...this.userInput]; @@ -1209,43 +1121,70 @@ this.userInput = newInput; } }); - optionLabel.appendChild(optionRadio); - optionLabel.appendChild(document.createTextNode(" " + label)); - optionLabel.appendChild(document.createElement("br")); - dropdownContent.appendChild(optionLabel); - }); - document.body.appendChild(dropdown); - dropdownButton.addEventListener("click", () => { - this.lastPressBtn = this.DropdownText; - dropdownContent.style.display = this.isDropdownOpen ? "none" : "block"; - this.isDropdownOpen = !this.isDropdownOpen; - }); + dropdwnBtn.dispatchEvent(new Event("input", { bubbles: true })); + } else { + dropdwnBtn = document.createElement("button"); + dropdwnBtn.className = "dropbtn"; + dropdwnBtn.innerHTML = xmlEscape(this.DropdownText).replace(/\n/g, "
"); + dropdwnCont = document.createElement("div"); + dropdwnCont.id = "myDropdown"; + dropdwnCont.className = "dropdown-content"; + dropdwnCont.style.display = "none"; + this.optionList.forEach((label, index) => { + const optTxt = document.createElement("label"); + optTxt.style.color = this.questionColor; + optTxt.textContent = ""; + const optRadio = document.createElement("input"); + optRadio.type = this.inputType === "Dropdown" ? "radio" : "checkbox"; + optRadio.name = "dropdownOptions"; + optRadio.value = index; + optRadio.classList.add("dropdown-radio"); + optRadio.addEventListener("click", () => { + if (this.inputType === "Multi-Select Dropdown") { + if (selectOpts.includes(label)) selectOpts = selectOpts.filter(item => item !== label); + else selectOpts.push(label); + inputField.value = selectOpts.length > 0 ? JSON.stringify(selectOpts) : ""; + } else { inputField.value = label } + if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; + else { + const newInput = [...this.userInput]; + newInput[index] = inputField.value; + this.userInput = newInput; + } + }); + optTxt.append(optRadio, document.createTextNode(" " + label), document.createElement("br")); + dropdwnCont.appendChild(optTxt); + }); + dropdwnBtn.addEventListener("click", () => { + this.lastPressBtn = this.DropdownText; + dropdwnCont.style.display = this.isDropdownOpen ? "none" : "block"; + this.isDropdownOpen = !this.isDropdownOpen; + }); + } - const sliderContainer = document.createElement("div"); - sliderContainer.classList.add("slider-container"); + const sliderContain = document.createElement("div"); + sliderContain.classList.add("slider-container"); const slider = document.createElement("input"); - if (this.isInputEnabled.includes("Vertical")) slider.style.transform = "rotate(270deg)"; + if (this.inputType.includes("Vertical")) slider.style.transform = "rotate(270deg)"; slider.type = "range"; - slider.min = this.sliderInfo[0]; - slider.max = this.sliderInfo[1]; - slider.value = this.sliderInfo[2]; - if (this.isInputEnabled.includes("Vertical")) { - for (let i = 0; i < 3; i++) { sliderContainer.appendChild(document.createElement("br")) } - sliderContainer.appendChild(slider); - for (let i = 0; i < 4; i++) { sliderContainer.appendChild(document.createElement("br")) } - } else { sliderContainer.appendChild(slider) } - const valueDisplay = document.createElement("span"); - valueDisplay.classList.add("slider-value"); - sliderContainer.appendChild(valueDisplay); - valueDisplay.style.color = this.questionColor; - valueDisplay.textContent = slider.value; + slider.min = this.sliderInfo[0]; slider.max = this.sliderInfo[1]; slider.value = this.sliderInfo[2]; + if (this.inputType.includes("Vertical")) { + for (let i = 0; i < 3; i++) { sliderContain.appendChild(document.createElement("br")) } + sliderContain.appendChild(slider); + for (let i = 0; i < 4; i++) { sliderContain.appendChild(document.createElement("br")) } + } else { sliderContain.appendChild(slider) } + const valTxt = document.createElement("span"); + valTxt.classList.add("slider-value"); + sliderContain.appendChild(valTxt); + valTxt.style.color = this.questionColor; + valTxt.textContent = slider.value; slider.addEventListener("input", () => { - valueDisplay.textContent = slider.value; + valTxt.textContent = slider.value; inputField.value = slider.value; - if (this.askBoxInfo[1] == 1) this.userInput = valueDisplay.textContent; + if (this.askBoxInfo[1] == 1) this.userInput = valTxt.textContent; else { const newInput = [...this.userInput]; - newInput[index] = valueDisplay.textContent; + newInput[index] = valTxt.textContent; this.userInput = newInput; } }); @@ -1253,26 +1192,24 @@ switch (item) { case "question": { overlay.appendChild(questionText); break } case "input": - if (this.isInputEnabled !== "Disabled") { - if (this.isInputEnabled === "Enabled" || this.isInputEnabled === "Color" || - this.isInputEnabled === "Number" || this.isInputEnabled === "Password" + if (this.inputType !== "Disabled") { + if (this.inputType === "Enabled" || this.inputType === "Color" || + this.inputType === "Number" || this.inputType === "Password" ) { overlay.appendChild(inputField); - } else if (this.isInputEnabled.includes("Dropdown")) { - overlay.appendChild(dropdownButton); - overlay.appendChild(dropdownContent); - overlay.appendChild(document.createElement("br")); + } else if (this.inputType === "Single Dropdown") { + overlay.append(dropdwnBtn, document.createElement("br")); + } else if (this.inputType.includes("Dropdown")) { + overlay.append(dropdwnBtn, dropdwnCont, document.createElement("br")); } else { - overlay.appendChild(sliderContainer); - overlay.appendChild(valueDisplay); - overlay.appendChild(document.createElement("br")); + overlay.append(sliderContain, valTxt, document.createElement("br")); } } break; - case "buttons": { overlay.appendChild(buttonContainer); break } + case "buttons": { overlay.appendChild(btnContain); break } } } - overlay.appendChild(overlayImageContainer); + overlay.appendChild(laidImgContain); if (this.appendTarget[0] === "window") { document.body.appendChild(overlay); if (this.appendTarget[1]) document.body.appendChild(focusBG); @@ -1280,7 +1217,7 @@ inputField.focus(); inputField.value = this.defaultValue; this.activeOverlays.push(overlay); - this.activeUI.push({ overlay: { button: buttonContainer, dropdown: dropdownButton, input: inputField } }); + this.activeUI.push({ overlay: { button: btnContain, dropdown: dropdwnBtn, input: inputField } }); if (this.appendTarget[0] === "window") { const resizeHandler = () => { overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; @@ -1308,6 +1245,8 @@ vm.renderer.addOverlay(overlay, "scale-centered"); } inputField.focus(); + if (this.appendTarget[0] === "window") overlay.style.zIndex = "9999"; + else overlay.parentNode.style.zIndex = "9999"; this.updateOverlay(overlay); }); } @@ -1317,7 +1256,7 @@ this.isDropdownOpen = false; if (!doneBefore) { this.askBoxInfo[0]--; - let usedBG = document.querySelectorAll(".SP-ask-boxBG"); + let usedBG = document.querySelectorAll(`div[class="SP-ask-boxBG"]`); usedBG = usedBG[usedBG.length - 1]; // ^ Prioritizes Textboxes on Window const index = this.activeOverlays.indexOf(overlay); @@ -1347,12 +1286,12 @@ dropShadow: "none", outline: ["", 0] }; } else { delete this.buttonJSON[args.NAME] } - Scratch.vm.extensionManager.refreshBlocks(); + vm.extensionManager.refreshBlocks(); } deleteAllButtons() { this.buttonJSON = {}; - Scratch.vm.extensionManager.refreshBlocks(); + vm.extensionManager.refreshBlocks(); } lastButton() { return this.lastPressBtn } @@ -1402,10 +1341,6 @@ } getUIOrder() { return JSON.stringify(this.uiOrder) } - - setEnable() { throw new Error("This Block has been removed since Better Input V3. Please use the New Powerful Blocks") } - getBoxCount() { return this.askBoxInfo[0] } //Legacy - getMaxCount() { return this.askBoxInfo[1] } //Legacy } Scratch.extensions.register(new BetterInputSP()); From 1267ca22cdf34b56c8be3d64609eaa425f2d1f17 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 11 Aug 2024 12:07:48 -0700 Subject: [PATCH 41/46] Update Better-Input.js --- extensions/SharkPool/Better-Input.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 8c9cfbbe9a..5747fc49e7 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -1,6 +1,6 @@ // Name: Better Input // ID: BetterInputSP -// Description: Expansion of the "ask and wait" Blocks +// Description: Expansion of the "ask and wait" Blocks. // By: SharkPool // Version V.4.2.0 @@ -21,7 +21,6 @@ const effectIcon = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1Ny40NDIiIGhlaWdodD0iNzAuNDUiIHZpZXdCb3g9IjAgMCA1Ny40NDIgNzAuNDUiPjxnIGZpbGw9IiNmZmYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIj48cGF0aCBkPSJNNSA0OS4wNDdjLTMuOTg4LTguMTE3LTMuOTk2LTE4LjI0My4xNTMtMjYuNDFDOS44NCAxMy4wNjIgMTcuNzMgOC44MTggMjAuOSA3LjQzOGEzMS40IDMxLjQgMCAwIDEgNi4wNzYtMi4wODNsMi4xMi0uNDU3YzEuNTU4LS4zMiAzLjExLjY0NiAzLjQ0NyAyLjE4Ny4zNCAxLjU0NS0uNjUxIDMuMDY2LTIuMjE2IDMuNDAybC0yLjA2My40NDVhMjUuNCAyNS40IDAgMCAwLTQuOTYgMS43MTZjLTIuMDgzLjkwMi04Ljk3NCA0LjM5Mi0xMi45NDkgMTIuNTE1LTMuMDE3IDUuOTMzLTMuOTE3IDE1LjM2Ni44MzIgMjMuMTUgNC4zMDMgNy40OTggMTMuMTEyIDEyLjA5NSAyMS40NjggMTEuMzIxIDcuOTAzLS41NjggMTUuMTU1LTUuODI4IDE3LjY5OC0xMi43OTUgMi41ODEtNi41NTIuODY2LTEzLjI2OS0xLjk2Ny0xNy4wNTItMy40MTMtNC42Ni03LjY2LTYuMDk0LTkuMzI4LTYuNDk1LS4yNDktLjA3NC02LjA4NS0xLjgyNy0xMS4yNC43NTQtMi4yMiAxLjA2NC01LjA5IDMuNDU2LTYuNjI4IDcuMDUtMS42NiAzLjcxMi0xLjIzIDguNDg0IDEuMDIgMTEuNjU1IDIuMjYzIDMuMzk5IDYuNTMyIDUuMzIzIDEwLjIwMyA0LjY3IDMuNjU1LS41NzUgNi4xMjctMy4yOTQgNi43MTMtNS42ODMuNjg5LTIuNTY4LS4zNjgtNC43MzktMS4xOTMtNS41Mi0xLjQwMS0xLjM4My0yLjYxMS0xLjQwNi0yLjY2My0xLjQxYTUgNSAwIDAgMC0xLjAyNi4wNTRjLS42NTQuMjQtMS41ODIuNzY0LTEuODU0IDEuMzE2LS4wNDguMDktLjE3LjM0LjA2NC45NjMuNTYzIDEuNDc3LS4xOTcgMy4xMy0xLjY5NCAzLjY4NS0xLjQ5LjU1OC0zLjE2Ny0uMTkyLTMuNzMzLTEuNjczLS45MzEtMi40NS0uNDE2LTQuMzY4LjE4LTUuNTQ2IDEuNTU4LTMuMDY2IDUuMTc2LTQuMTc2IDUuNTg1LTQuMjk0LjE4Ny0uMDU3LjM4NS0uMDkxLjU4LS4xMDguMzk4LS4wNiAxLjEtLjE1NSAyLjA1Mi0uMTE4IDIuMTc4LjAyNyA0LjY2IDEuMTY1IDYuNTYzIDMuMDQ2IDIuMjQ2IDIuMTIgNC4wMDYgNi4zOCAyLjc1OCAxMS4wMTEtMS4yMTcgNC45NTctNS44OTUgOS4wNTYtMTEuMzUzIDkuOTE0LTUuODcgMS4wNDctMTIuNDgyLTEuODQ3LTE1Ljk3My03LjA5NC0zLjM2NS00LjcyOC00LjAwOS0xMS42NDctMS41NDgtMTcuMTM2IDIuNy02LjMyIDcuODU5LTkuMTggOS4zNzMtOS45MDcgNy4yNzktMy42MzUgMTUuMDU5LTEuMjM1IDE1LjM4Ni0xLjEzNCAyLjA5My40OTQgNy45MTMgMi40NDMgMTIuNDM3IDguNjI1IDMuNDc3IDQuNjUgNi4yOTcgMTMuMzM3IDIuNzE0IDIyLjQzLTMuMjczIDguOTYyLTEyLjU5IDE1Ljc3LTIyLjYzOCAxNi40OTMtLjc4OC4wNzQtMS41ODUuMTE1LTIuMzguMTE1LTkuNzUgMC0xOS42MjctNS42Mi0yNC41OC0xNC4yNSAwIDAtLjgyMS0xLjQxOC0xLjE4My0yLjE1M3oiIHN0cm9rZT0iIzY5MDBiNCIgc3Ryb2tlLXdpZHRoPSIxMCIvPjxwYXRoIGQ9Ik02LjE4MiA1MS4yMDFjLTUuMTM0LTguNDItNS41NTMtMTkuNjU3LTEuMDMtMjguNTY1QzkuODQgMTMuMDYyIDE3LjczIDguODE4IDIwLjkgNy40MzhhMzEuNCAzMS40IDAgMCAxIDYuMDc2LTIuMDgzbDIuMTItLjQ1N2MxLjU1OC0uMzIgMy4xMS42NDYgMy40NDcgMi4xODcuMzQgMS41NDUtLjY1MSAzLjA2Ni0yLjIxNiAzLjQwMmwtMi4wNjMuNDQ1YTI1LjQgMjUuNCAwIDAgMC00Ljk2IDEuNzE2Yy0yLjA4My45MDItOC45NzQgNC4zOTItMTIuOTQ5IDEyLjUxNS0zLjAxNyA1LjkzMy0zLjkxNyAxNS4zNjYuODMyIDIzLjE1IDQuMzAzIDcuNDk4IDEzLjExMiAxMi4wOTUgMjEuNDY4IDExLjMyMSA3LjkwMy0uNTY4IDE1LjE1NS01LjgyOCAxNy42OTgtMTIuNzk1IDIuNTgxLTYuNTUyLjg2Ni0xMy4yNjktMS45NjctMTcuMDUyLTMuNDEzLTQuNjYtNy42Ni02LjA5NC05LjMyOC02LjQ5NS0uMjQ5LS4wNzQtNi4wODUtMS44MjctMTEuMjQuNzU0LTIuMjIgMS4wNjQtNS4wOSAzLjQ1Ni02LjYyOCA3LjA1LTEuNjYgMy43MTItMS4yMyA4LjQ4NCAxLjAyIDExLjY1NSAyLjI2MyAzLjM5OSA2LjUzMiA1LjMyMyAxMC4yMDMgNC42NyAzLjY1NS0uNTc1IDYuMTI3LTMuMjk0IDYuNzEzLTUuNjgzLjY4OS0yLjU2OC0uMzY4LTQuNzM5LTEuMTkzLTUuNTItMS40MDEtMS4zODMtMi42MTEtMS40MDYtMi42NjMtMS40MWE1IDUgMCAwIDAtMS4wMjYuMDU0Yy0uNjU0LjI0LTEuNTgyLjc2NC0xLjg1NCAxLjMxNi0uMDQ4LjA5LS4xNy4zNC4wNjQuOTYzLjU2MyAxLjQ3Ny0uMTk3IDMuMTMtMS42OTQgMy42ODUtMS40OS41NTgtMy4xNjctLjE5Mi0zLjczMy0xLjY3My0uOTMxLTIuNDUtLjQxNi00LjM2OC4xOC01LjU0NiAxLjU1OC0zLjA2NiA1LjE3Ni00LjE3NiA1LjU4NS00LjI5NC4xODctLjA1Ny4zODUtLjA5MS41OC0uMTA4LjM5OC0uMDYgMS4xLS4xNTUgMi4wNTItLjExOCAyLjE3OC4wMjcgNC42NiAxLjE2NSA2LjU2MyAzLjA0NiAyLjI0NiAyLjEyIDQuMDA2IDYuMzggMi43NTggMTEuMDExLTEuMjE3IDQuOTU3LTUuODk1IDkuMDU2LTExLjM1MyA5LjkxNC01Ljg3IDEuMDQ3LTEyLjQ4Mi0xLjg0Ny0xNS45NzMtNy4wOTQtMy4zNjUtNC43MjgtNC4wMDktMTEuNjQ3LTEuNTQ4LTE3LjEzNiAyLjctNi4zMiA3Ljg1OS05LjE4IDkuMzczLTkuOTA3IDcuMjc5LTMuNjM1IDE1LjA1OS0xLjIzNSAxNS4zODYtMS4xMzQgMi4wOTMuNDk0IDcuOTEzIDIuNDQzIDEyLjQzNyA4LjYyNSAzLjQ3NyA0LjY1IDYuMjk3IDEzLjMzNyAyLjcxNCAyMi40My0zLjI3MyA4Ljk2Mi0xMi41OSAxNS43Ny0yMi42MzggMTYuNDkzLS43ODguMDc0LTEuNTg1LjExNS0yLjM4LjExNS05Ljc1IDAtMTkuNjI3LTUuNjItMjQuNTgtMTQuMjUiLz48L2c+PC9zdmc+"; - let newColorType = ""; let laidImgContain = ""; const vm = Scratch.vm; const fontMenu = [ From 31b182ca28c34bae9d7c975a95fbbf581fd6459d Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sun, 11 Aug 2024 12:08:44 -0700 Subject: [PATCH 42/46] Update Better-Input.js --- extensions/SharkPool/Better-Input.js | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 5747fc49e7..bab2786a70 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -2,6 +2,7 @@ // ID: BetterInputSP // Description: Expansion of the "ask and wait" Blocks. // By: SharkPool +// License: MPL-2.0 // Version V.4.2.0 From 3961fd9e9c973e59c479f1061f8c633171564e28 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:07:19 -0700 Subject: [PATCH 43/46] Better-Input -- Wizard of Oz fix --- extensions/SharkPool/Better-Input.js | 198 +++++++++++---------------- 1 file changed, 81 insertions(+), 117 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index bab2786a70..01e1c2c761 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -2,9 +2,8 @@ // ID: BetterInputSP // Description: Expansion of the "ask and wait" Blocks. // By: SharkPool -// License: MPL-2.0 -// Version V.4.2.0 +// Version V.4.2.01 (function (Scratch) { "use strict"; @@ -43,7 +42,7 @@ class BetterInputSP { constructor() { - this.activeOverlays = []; this.activeUI = []; this.askBoxPromises = []; + this.activeOverlays = []; this.askBoxPromises = []; this.isWaitingForInput = false; this.isDropdownOpen = false; this.userInput = " "; this.defaultValue = ""; this.textBoxX = 0; this.textBoxY = 0; @@ -976,10 +975,8 @@ }); this.askBoxPromises = []; this.activeOverlays = this.activeOverlays.filter((overlay) => !overlaysToRemove.includes(overlay)); - this.activeUI = []; this.askBoxInfo[0] = 0; this.isDropdownOpen = false; - // Remove "Bugged" Boxes, bugged boxes is a intentional feature, ask for more info const bugged = document.querySelectorAll(`div[class^="SP-ask-box"]`); bugged.forEach((box) => { box.parentNode.removeChild(box) }); } @@ -1002,8 +999,7 @@ this.askBoxInfo[0]++; let selectOpts = []; return new Promise((resolve) => { - const askBoxPromise = { resolve }; - this.askBoxPromises.push(askBoxPromise); + this.askBoxPromises.push({ resolve }); const overlay = document.createElement("div"); overlay.classList.add("SP-ask-box"); overlay.style.pointerEvents = "auto"; @@ -1030,12 +1026,7 @@ const overlayInput = this.forceInput === "Enter Key" ? "Enter" : this.forceInput === "Shift + Enter Key" ? "ShiftEnter" : this.forceInput; const handleKeydown = (event) => { if ((overlayInput === "ShiftEnter" && event.shiftKey && event.key === "Enter") || event.key === overlayInput) { - if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; - else { - const newInput = [...this.userInput]; - newInput[index] = inputField.value; - this.userInput = newInput; - } + setInpValue(inputField.value); this.closeOverlay(overlay, hasDecreased); hasDecreased = true; resolve(); @@ -1065,14 +1056,16 @@ inputField.style.fontSize = this.fontSize; inputField.style.margin = "0 auto"; inputField.type = this.inputType.toLowerCase(); - inputField.addEventListener("input", () => { + const setInpValue = (val) => { + inputField.value = val; if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; else { const newInput = [...this.userInput]; newInput[index] = inputField.value; this.userInput = newInput; } - }); + } + inputField.addEventListener("input", () => { setInpValue(inputField.value) }); const btnContain = document.createElement("div"); btnContain.classList.add("button-container"); for (const buttonName in this.buttonJSON) { @@ -1088,12 +1081,7 @@ btn.style.display = "inline-block"; btn.addEventListener("click", () => { this.lastPressBtn = btnInfo.name; - if (this.askBoxInfo[1] == 1) this.userInput = this.inputType === "Disabled" ? btnInfo.name : inputField.value; - else { - const newInput = [...this.userInput]; - newInput[index] = this.inputType === "Disabled" ? btnInfo.name : inputField.value; - this.userInput = newInput; - } + setInpValue(this.inputType === "Disabled" ? btnInfo.name : this.userInput); this.closeOverlay(overlay, hasDecreased); hasDecreased = true; resolve(); @@ -1101,108 +1089,87 @@ btnContain.appendChild(btn); } } - - const dropdown = document.createElement("div"); - dropdown.className = "dropdown"; - let dropdwnBtn, dropdwnCont; - if (this.inputType === "Single Dropdown") { - dropdwnBtn = document.createElement("select"); - this.optionList.forEach((label) => { - let opt = document.createElement("option"); - opt.value = label; opt.text = label; - dropdwnBtn.appendChild(opt); - }); - dropdwnBtn.addEventListener("input", () => { - inputField.value = dropdwnBtn.value; - if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; - else { - const newInput = [...this.userInput]; - newInput[index] = inputField.value; - this.userInput = newInput; - } - }); - dropdwnBtn.dispatchEvent(new Event("input", { bubbles: true })); - } else { - dropdwnBtn = document.createElement("button"); - dropdwnBtn.className = "dropbtn"; - dropdwnBtn.innerHTML = xmlEscape(this.DropdownText).replace(/\n/g, "
"); - dropdwnCont = document.createElement("div"); - dropdwnCont.id = "myDropdown"; - dropdwnCont.className = "dropdown-content"; - dropdwnCont.style.display = "none"; - this.optionList.forEach((label, index) => { - const optTxt = document.createElement("label"); - optTxt.style.color = this.questionColor; - optTxt.textContent = ""; - const optRadio = document.createElement("input"); - optRadio.type = this.inputType === "Dropdown" ? "radio" : "checkbox"; - optRadio.name = "dropdownOptions"; - optRadio.value = index; - optRadio.classList.add("dropdown-radio"); - optRadio.addEventListener("click", () => { - if (this.inputType === "Multi-Select Dropdown") { - if (selectOpts.includes(label)) selectOpts = selectOpts.filter(item => item !== label); - else selectOpts.push(label); - inputField.value = selectOpts.length > 0 ? JSON.stringify(selectOpts) : ""; - } else { inputField.value = label } - if (this.askBoxInfo[1] == 1) this.userInput = inputField.value; - else { - const newInput = [...this.userInput]; - newInput[index] = inputField.value; - this.userInput = newInput; - } + let dropdwnCont, dropdwnBtn, sliderContain, valTxt; + if (this.inputType.includes("Dropdown")) { + const dropdown = document.createElement("div"); + dropdown.className = "dropdown"; + if (this.inputType === "Single Dropdown") { + dropdwnBtn = document.createElement("select"); + this.optionList.forEach((label) => { + let opt = document.createElement("option"); + opt.value = label; opt.text = label; + dropdwnBtn.appendChild(opt); }); - optTxt.append(optRadio, document.createTextNode(" " + label), document.createElement("br")); - dropdwnCont.appendChild(optTxt); - }); - dropdwnBtn.addEventListener("click", () => { - this.lastPressBtn = this.DropdownText; - dropdwnCont.style.display = this.isDropdownOpen ? "none" : "block"; - this.isDropdownOpen = !this.isDropdownOpen; - }); - } - - const sliderContain = document.createElement("div"); - sliderContain.classList.add("slider-container"); - const slider = document.createElement("input"); - if (this.inputType.includes("Vertical")) slider.style.transform = "rotate(270deg)"; - slider.type = "range"; - slider.min = this.sliderInfo[0]; slider.max = this.sliderInfo[1]; slider.value = this.sliderInfo[2]; - if (this.inputType.includes("Vertical")) { - for (let i = 0; i < 3; i++) { sliderContain.appendChild(document.createElement("br")) } + dropdwnBtn.addEventListener("input", () => { setInpValue(dropdwnBtn.value) }); + setInpValue(dropdwnBtn.value); + } else { + dropdwnBtn = document.createElement("button"); + dropdwnBtn.className = "dropbtn"; + dropdwnBtn.innerHTML = xmlEscape(this.DropdownText).replace(/\n/g, "
"); + dropdwnCont = document.createElement("div"); + dropdwnCont.id = "myDropdown"; + dropdwnCont.className = "dropdown-content"; + dropdwnCont.style.display = "none"; + this.optionList.forEach((label, index) => { + const optTxt = document.createElement("label"); + optTxt.style.color = this.questionColor; + optTxt.textContent = ""; + const optRadio = document.createElement("input"); + optRadio.type = this.inputType === "Dropdown" ? "radio" : "checkbox"; + optRadio.name = "dropdownOptions"; + optRadio.value = index; + optRadio.classList.add("dropdown-radio"); + optRadio.addEventListener("click", () => { + if (this.inputType === "Multi-Select Dropdown") { + if (selectOpts.includes(label)) selectOpts = selectOpts.filter(item => item !== label); + else selectOpts.push(label); + inputField.value = selectOpts.length > 0 ? JSON.stringify(selectOpts) : ""; + } else { inputField.value = label } + setInpValue(inputField.value) + }); + optTxt.append(optRadio, document.createTextNode(" " + label), document.createElement("br")); + dropdwnCont.appendChild(optTxt); + }); + dropdwnBtn.addEventListener("click", () => { + this.lastPressBtn = this.DropdownText; + dropdwnCont.style.display = this.isDropdownOpen ? "none" : "block"; + this.isDropdownOpen = !this.isDropdownOpen; + }); + } + } else if (this.inputType.includes("Slider")) { + sliderContain = document.createElement("div"); + sliderContain.classList.add("slider-container"); + const slider = document.createElement("input"); + slider.type = "range"; + slider.min = this.sliderInfo[0]; slider.max = this.sliderInfo[1]; slider.value = this.sliderInfo[2]; + if (this.inputType.includes("Vertical")) { + slider.style.writingMode = "vertical-lr"; + slider.style.direction = "rtl"; + } sliderContain.appendChild(slider); - for (let i = 0; i < 4; i++) { sliderContain.appendChild(document.createElement("br")) } - } else { sliderContain.appendChild(slider) } - const valTxt = document.createElement("span"); - valTxt.classList.add("slider-value"); - sliderContain.appendChild(valTxt); - valTxt.style.color = this.questionColor; - valTxt.textContent = slider.value; - slider.addEventListener("input", () => { + valTxt = document.createElement("span"); + valTxt.classList.add("slider-value"); + sliderContain.appendChild(valTxt); + valTxt.style.color = this.questionColor; valTxt.textContent = slider.value; - inputField.value = slider.value; - if (this.askBoxInfo[1] == 1) this.userInput = valTxt.textContent; - else { - const newInput = [...this.userInput]; - newInput[index] = valTxt.textContent; - this.userInput = newInput; - } - }); + slider.addEventListener("input", () => { + valTxt.textContent = slider.value; + setInpValue(valTxt.textContent); + }); + setInpValue(valTxt.textContent); + } for (const item of this.uiOrder) { switch (item) { case "question": { overlay.appendChild(questionText); break } case "input": if (this.inputType !== "Disabled") { - if (this.inputType === "Enabled" || this.inputType === "Color" || - this.inputType === "Number" || this.inputType === "Password" - ) { + const createBr = () => { return document.createElement("br") }; + if (this.inputType === "Single Dropdown") overlay.append(dropdwnBtn, createBr()); + else if (this.inputType.includes("Dropdown")) overlay.append(dropdwnBtn, dropdwnCont, createBr()); + else if (this.inputType.includes("Slider")) overlay.append(sliderContain, valTxt, createBr()); + else { + setInpValue(this.defaultValue); overlay.appendChild(inputField); - } else if (this.inputType === "Single Dropdown") { - overlay.append(dropdwnBtn, document.createElement("br")); - } else if (this.inputType.includes("Dropdown")) { - overlay.append(dropdwnBtn, dropdwnCont, document.createElement("br")); - } else { - overlay.append(sliderContain, valTxt, document.createElement("br")); } } break; @@ -1215,9 +1182,7 @@ if (this.appendTarget[1]) document.body.appendChild(focusBG); } inputField.focus(); - inputField.value = this.defaultValue; this.activeOverlays.push(overlay); - this.activeUI.push({ overlay: { button: btnContain, dropdown: dropdwnBtn, input: inputField } }); if (this.appendTarget[0] === "window") { const resizeHandler = () => { overlay.style.left = `${this.textBoxX !== null ? 50 + this.textBoxX : 50}%`; @@ -1265,7 +1230,6 @@ this.activeOverlays.splice(index, 1); this.askBoxPromises.splice(index, 1); } - delete this.activeUI[overlay]; if (this.appendTarget[0] === "window") document.body.removeChild(overlay); else vm.renderer.removeOverlay(overlay); if (usedBG) { From 36a782087ac89584ba96aeeee0d07cdd67c8bece Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 17 Aug 2024 00:09:35 -0700 Subject: [PATCH 44/46] prettier shut up --- extensions/SharkPool/Better-Input.js | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index 01e1c2c761..daf5e64966 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -2,6 +2,7 @@ // ID: BetterInputSP // Description: Expansion of the "ask and wait" Blocks. // By: SharkPool +// License: MPL-2.0 // Version V.4.2.01 From 3768ef9f904f01bbd13e485ab7f4d5578be758b4 Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Sat, 17 Aug 2024 01:37:32 -0700 Subject: [PATCH 45/46] Better-Input -- uno simplification --- extensions/SharkPool/Better-Input.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index daf5e64966..dd37843717 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -44,7 +44,7 @@ class BetterInputSP { constructor() { this.activeOverlays = []; this.askBoxPromises = []; - this.isWaitingForInput = false; this.isDropdownOpen = false; + this.isDropdownOpen = false; this.userInput = " "; this.defaultValue = ""; this.textBoxX = 0; this.textBoxY = 0; this.askBoxInfo = [0, 1]; this.appendTarget = ["window", false]; @@ -995,7 +995,6 @@ const question = args.question; let hasDecreased = false; // for the box counter const index = this.askBoxInfo[0]; - this.isWaitingForInput = true; this.lastPressBtn = ""; this.askBoxInfo[0]++; let selectOpts = []; @@ -1218,7 +1217,6 @@ } } closeOverlay(overlay, doneBefore) { - if (this.askBoxInfo[0] < 2) this.isWaitingForInput = false; this.isDropdownOpen = false; if (!doneBefore) { this.askBoxInfo[0]--; @@ -1261,7 +1259,7 @@ lastButton() { return this.lastPressBtn } - isWaitingInput() { return this.isWaitingForInput } + isWaitingInput() { return this.activeOverlays.length > 0 } isDropdown() { return this.isDropdownOpen } From bbbfc2bb70f6609427b42fd5a0cfca7934e4d40a Mon Sep 17 00:00:00 2001 From: SharkPool <139097378+SharkPool-SP@users.noreply.github.com> Date: Wed, 18 Sep 2024 20:49:55 -0700 Subject: [PATCH 46/46] Better-Input -- Bug Fix --- extensions/SharkPool/Better-Input.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/SharkPool/Better-Input.js b/extensions/SharkPool/Better-Input.js index dd37843717..0f78b614d3 100644 --- a/extensions/SharkPool/Better-Input.js +++ b/extensions/SharkPool/Better-Input.js @@ -4,7 +4,7 @@ // By: SharkPool // License: MPL-2.0 -// Version V.4.2.01 +// Version V.4.2.02 (function (Scratch) { "use strict"; @@ -716,6 +716,7 @@ if (buttonInfo) { button.style.color = buttonInfo.textColor; button.style.fontFamily = this.fontFamily; + button.style.fontSize = this.fontSize; button.style.borderRadius = `${buttonInfo.borderRadius}px`; button.style.border = buttonInfo.border; button.style.padding = buttonInfo.padding;