From bfb68ac6a909ab23ac4c2715d29b8515089f5739 Mon Sep 17 00:00:00 2001 From: LilyMakesThings <127533508+LilyMakesThings@users.noreply.github.com> Date: Sat, 8 Jul 2023 01:56:23 +0100 Subject: [PATCH 1/8] Add Lily/Cast extension (#605) --- extensions/Lily/Cast.js | 73 +++++++++++++++++++++++++++++++++++++++++ images/Lily/Cast.svg | 1 + website/index.ejs | 6 ++++ 3 files changed, 80 insertions(+) create mode 100644 extensions/Lily/Cast.js create mode 100644 images/Lily/Cast.svg diff --git a/extensions/Lily/Cast.js b/extensions/Lily/Cast.js new file mode 100644 index 0000000000..5035acae5a --- /dev/null +++ b/extensions/Lily/Cast.js @@ -0,0 +1,73 @@ +(function (Scratch) { + 'use strict'; + + const Cast = Scratch.Cast; + + class CastUtil { + getInfo() { + return { + id: 'lmsCast', + name: 'Cast', + blocks: [ + { + opcode: 'toType', + blockType: Scratch.BlockType.REPORTER, + text: 'cast [INPUT] to [TYPE]', + allowDropAnywhere: true, + disableMonitor: true, + arguments: { + INPUT: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'apple' + }, + TYPE: { + type: Scratch.ArgumentType.STRING, + menu: 'type' + } + } + }, + { + opcode: 'typeOf', + blockType: Scratch.BlockType.REPORTER, + text: 'type of [INPUT]', + disableMonitor: true, + arguments: { + INPUT: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'apple' + } + } + } + ], + menus: { + type: { + acceptReporters: true, + items: ['number', 'string', 'boolean', 'default'] + } + } + }; + } + + toType(args) { + const input = args.INPUT; + switch (args.TYPE) { + case ('number'): return Cast.toNumber(input); + case ('string'): return Cast.toString(input); + case ('boolean'): return Cast.toBoolean(input); + default: return input; + } + } + + typeOf(args) { + const input = args.INPUT; + switch (typeof input) { + case ('number'): return 'number'; + case ('string'): return 'string'; + case ('boolean'): return 'boolean'; + default: return ''; + } + } + } + + Scratch.extensions.register(new CastUtil()); +})(Scratch); diff --git a/images/Lily/Cast.svg b/images/Lily/Cast.svg new file mode 100644 index 0000000000..c133d27df6 --- /dev/null +++ b/images/Lily/Cast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/index.ejs b/website/index.ejs index 1e620f2d0d..f6dd5b3ab3 100644 --- a/website/index.ejs +++ b/website/index.ejs @@ -572,6 +572,12 @@

A few adapter blocks. Created by TrueFantom.

+
+ <%- banner('Lily/Cast') %> +

Cast

+

Convert values between types. Created by LilyMakesThings

+
+
<%- banner('-SIPC-/time') %>

Time

From f63699ae87dda2c3b89f4f83c04d5e6a4f2c6926 Mon Sep 17 00:00:00 2001 From: CST1229 <68464103+CST1229@users.noreply.github.com> Date: Sat, 8 Jul 2023 03:55:23 +0200 Subject: [PATCH 2/8] files: Add download URL block (#700) --- extensions/files.js | 71 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/extensions/files.js b/extensions/files.js index 25842fd6b2..2d1cea7860 100644 --- a/extensions/files.js +++ b/extensions/files.js @@ -165,21 +165,58 @@ }); /** - * @param {string} text Text to download - * @param {string} file Name of the file + * @param {string} url a data:, blob:, or same-origin URL + * @param {string} file */ - const download = (text, file) => { - const blob = new Blob([text]); - const url = URL.createObjectURL(blob); + const downloadURL = (url, file) => { const link = document.createElement('a'); link.href = url; link.download = file; document.body.appendChild(link); link.click(); link.remove(); + }; + + /** + * @param {Blob} blob Data to download + * @param {string} file Name of the file + */ + const downloadBlob = (blob, file) => { + const url = URL.createObjectURL(blob); + downloadURL(url, file); URL.revokeObjectURL(url); }; + /** + * @param {string} url + * @returns {boolean} + */ + const isDataURL = (url) => { + try { + const parsed = new URL(url); + return parsed.protocol === 'data:'; + } catch (e) { + return false; + } + }; + + /** + * @param {string} url + * @param {string} file + */ + const downloadUntrustedURL = (url, file) => { + // Don't want to return a Promise here when not actually needed + if (isDataURL(url)) { + downloadURL(url, file); + } else { + return Scratch.fetch(url) + .then(res => res.blob()) + .then(blob => { + downloadBlob(blob, file); + }); + } + }; + class Files { getInfo () { return { @@ -253,6 +290,24 @@ } } }, + { + opcode: 'downloadURL', + blockType: Scratch.BlockType.COMMAND, + text: 'download URL [url] as [file]', + arguments: { + url: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'data:text/plain;base64,SGVsbG8sIHdvcmxkIQ==' + }, + file: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'save.txt' + } + } + }, + + '---', + { opcode: 'setOpenMode', blockType: Scratch.BlockType.COMMAND, @@ -314,7 +369,11 @@ } download (args) { - download(args.text, args.file); + downloadBlob(new Blob([Scratch.Cast.toString(args.text)]), Scratch.Cast.toString(args.file)); + } + + downloadURL (args) { + return downloadUntrustedURL(Scratch.Cast.toString(args.url), Scratch.Cast.toString(args.file)); } setOpenMode (args) { From 60507385c91a4c79c07d59b1e4ac523ffcc2ac7d Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Fri, 7 Jul 2023 21:16:01 -0500 Subject: [PATCH 3/8] Fix some image pixelation issues (#689) * Convert cursor to PNG * Convert gamejolt to PNG * Convert pointerlock to PNG --- images/cursor.png | Bin 0 -> 8767 bytes images/cursor.svg | 1 - images/gamejolt.png | Bin 0 -> 1926 bytes images/gamejolt.svg | 1 - images/pointerlock.png | Bin 0 -> 28312 bytes images/pointerlock.svg | 1 - 6 files changed, 3 deletions(-) create mode 100644 images/cursor.png delete mode 100644 images/cursor.svg create mode 100644 images/gamejolt.png delete mode 100644 images/gamejolt.svg create mode 100644 images/pointerlock.png delete mode 100644 images/pointerlock.svg diff --git a/images/cursor.png b/images/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..b53b880cd6f65718e65c99f2f532256eab2b71dd GIT binary patch literal 8767 zcmcgyi93{E^k-~iZR|{znS?B9h!SCpJv-S+Lv}(4*)>L4vJ_dOwAlBp>@~J5h04B# ztXZ;W|J~8|d4B)E@A*B?c)ag<&pr2?&pG$pbKdtp*3(g=r-9RukdV-8s4E+gkU&gH zNJvGY5I~8yHva_vQG2MHd6AGXG!y?w+ud{T03xTiimA7uyS=wB_MRPyudlC|(_I%Y zTdaqjnEO44^wsNd5)x#$hO**Kzmb)3GYg~k%=UH2#+KXUY;DPY@g!lfaV>gNKGDlY zN6_9_k>v$ixz&s@67e%$gD$s)bmsaLi=2++L|KyWyi&HdU;p@z2d;15I9 zE=@sm39sF6dHE7_ZCB`EOc+N6x^6X+zj7tRYAk6XHBNC6=~oZ;+a1Zc}foo&*CZ>Y*qympeBuNGHZBu10cYd z4v_VKbB}s%Sf_@2Y`{6=T#x%dmDBv2;5#h&7N4Pfda!3vA%w_`=oZ8AxZJ51Jv8GU zp*j^!l6By6r&EkS=tAvFvj3C~lak=^d;^APJj?0$+Ww!eV`2p)7^V$@2YK1uvsNFg z5KojY@P&l?UXi~S5*yQO$BI@bbeAX?GLzR>gmx*8MV8tOjQ6y_IZe8RL*vP{=buu) z3@HYl8AZgDsyeyw4rsG1$=`2DLYM${D*Ri$ND?AJ^e@q%))$^0o2x#Z^p=Yodv2L@h8c- zm$pu7W7w|C5Khz6-fqHrm#dhO6yt)335tz5YsdN+^I;>~{N^&F+rthE>wJEmv%JaH ztIC6=zdRPAJH3`H1t7R&bV@gX)LWjC(3x;_nf|gxuqtE$P6=nA0O7Txm@)?ETq}=q zD+xvML#>5|?y*jO62>mT=kQ7)n*n_vZjnPThN2dwB#fUMeW1#!|G88%kNwN4%ee;M zslO@Pbw$A>b_rXCm(E9wEC^O>Gf50fEk7{7FTe`imh84XFkwh0G|}-H zo?0&cq41m)^s0h!m-u1Ma@}E}a+dFwO^T}zz1sa=2G1-<2Wr@Uz@Lz`k%l7w*qA|s zZ#k)SYm;<8nItO<1}{@>!7 zi+VD(H7R?w7GG}5J?KZhBI*gltl@hcHlIu21d0;Yg$w+q5V&>1aNv!-t87BA)sn5> zxug)ruC0iYVwjPVZm}^PIYt}|*sO5Y?>pR9O1u_rEpm2fSMMG%xQilt|42#PigmgH0(l{L@K2KPh{mdW zP6j{PkqLLDFk!v?k3NkZ>mr8Z=&5n#GgWhGHa8astyQ>yB$rIG(R+}6vJ{}ByfHUJ zlX|kPFITE&W6WAL5p>j8{kPG;<(($w;vEY2`?brqWWoC6FsvEsOi#7oo2h!XMFAV3 z$r7?^#ziV!rHf9w`YaqQx?Tj-4TQAa)MZ2^2f@1zZ^5_xYDJK{*`{^7{*-|Qx?;sQ z<73{+i*^*pIr-4nWm3rNp;E%nv~0M{&_F;c1Y-kZwOYz)s;IYT{y3fV2|z`Hm5{hE zf~`vy%!!>0ZX>n$vgKD+`k(Af1TPTtTx@7B$N>5}1q*%`&hae%6vjQRI97A0!+Wm0 zT4D6xPPP&WGw1;ex)MTAuESgPJmqHiA~a-tLy?&K!6Jd|2GVVYdt-uUBTWN8>|#%Zsz{j0rmjcC6%JJqal-{DP;xvSTGhi1rrG7Mg2* z^EMEbPEeR~6h%8~4(f&1?&(jL+#i?gyI)gCv>#;z9k=2$tR_9mQ#Ml(#~oL0f;7@6 zwH#bLv)Qy$Y`T<(0P(5CjCl{@^SP00&^y%|c7_*Z*~;@eU3@K_uKqcaWxTpsNsC!q zvwpDTV~gx2V#q1OmCsUd6^15iFMu;M<(s+ORibm74tj*XaDtunDVxRzsZ9uazPjB} zSTn0hw36d2PV-WMafj?uAU>ujfs`RNkIaDQ)71q0Mkuq z+#@{M>uO!mM!jk&Yfo*rbQ}9YJ^IMw>{$vH*LTD?{t|(zaJhp~;#kj!n%#sAQVEgc zVyRTzno`!QqNs2+#Zx17Z9en?OcRO$1mlrGhzQZ;K1!eAoCvzDqs`r>OupVTxSG#m z3D;Sg97%lwkJDrrZd8BBTJ2x6T_SW1*#VY^R1 z9`+~EyqhurolB3Y3ZJWG6meu4Q{HN)8O*k$WcUvaPi&PT9{D=MsNisfZIcZ)1t zeCs^@6z|cmT@ta~Rg$NjqcvK{1l>lb1PDv~8P~ll;)Xb{TJngRa!RFN`bq|@h}|{9 zqi-*e`K8F_hR)xP#DK>3PP((Q6c{;}822#LV}<)StEHFh6-Ze8+xl|?Fr0Av56Sc( z*ex25;CQXiihVCz%0-X?)Om3kkSuwqmxyEcP`>P9QDs>CP}w;F4jkXLtFD|lCifE> zJl@0T*8sA$%n+5H6JYhYl~soV#438vV8|jPahR66qI*}9D6rb>l>_k zGR~_}`DDn65y!a8P$l;OA?aLjx5>h3Qe9cm3;FCzZcB;Bb+_-A5}sfL@FkBtSqWqC zRAuBc$CJt&Jhg2OI)w(O>eg@NDYC*k$b1-o_WfI%F5X$)0-6983Gon>m;xB35sDnA zp_S^$BTGSGL4pZZ%i|slCLXz__u(522z$$_-tu8wR3!Ve0??-b zCW80rfDRh5y0pLZ*H*BV?D=OHD@n(lKx<`d11zv#Y83%lo_LI=Z#>g^}ghHJ!RbUv|9mVG3Iar|LC zzM_CHgqD+Fs%QkVy`rujKbwqBlrB9-34MsUz?(c;oI-)MB-$&66L9UnD4Q*#FtI=K z<*VRhx>x#UQ*BWk2s#?<>*$4V+(7FeNG;!j)t!{;Z&xS@eVC8RCGaFxhC-k&8rI3y z$wr|R1Kdds%dRr=jj?dbIfM1hH9}1(*+tBX*o1nBZmexTS*A_9egW?I*Sl4!YW(@~ zrQ({RLzkvY0}6WF;mMbo4Jw65Va}_)E~BoFE8OEjpOg{ZMd2C+t#8W-6RhIs1qE$E zOFdM4g4dbH*CJcSn$al`+(`A3j_10G*6|VND;R1RYalGLY{^K5lfUes*Xj?AHW*Y8 zQ*={+Wj|GZzcf&NN%h+J)FQ%_F}VWi2>BgaD67`@5bZ!o1_#eVj~*?&IPw~ z3q1l&}_bSeWW$zD2X~NSWe=fScvdOZO7&j#-V2 zKO6Hb#aJ=&t-br!lirM$KJG7duNNZ6AS4B+s+VrP{4A zp=W#NsrO@raq|fYQ59|&n_GXw&RrP`Co*hyPvPehKZ&Y^%L}SZOc?)@o_$Iv=q!rD zP}Yuqg0tGnVW@y4))KAZ{p4 zfX(fsQ(_R^3^<>orNcaeXw4%FbjsMXsUGJuqzA&&C$O^@h4$%Wq@+0sFCvr_YALaz zruLkKC<@jcjHyDX0b1QI;>hAb?vaF_PO!A!q2Rb z5ovPx%nt;>qDNGk0g$b(RbbqL?gk=XRp%)pVjxpv%~4cwk{Mw9d9>rVRMw>}wfSoK zIB6*;P9IUo@!Z^$_`uUnC0N##T{k2~9y}nb3dM<;7<<psDU!I$ z`_CdK%Dfc}fZ6I?sc>?_9pqL5MLVz{EIxkgAN-&IZoOW(FVAcic&o^{>)rPC(`ZZE zp}?UR<{YOE->l|Ly~ihQFG!TT|l%8Sy@G88aj< zIxxZ5Rg%xj>2mk+6DqW$@)A`g!yDq7LUx?Pt?b_DceG{`xtkke$Bz5be(ZKI+a&XJ zl{VyP>scq^=!CdHDR6ENPwegiT?Lso(A$S2!bP90@2eC_e0XR|KK0G8T|A6Rs z4ndsPndsySRtPZ$uqL0b!(8r0+nLxN+a_BZMZ3u0fyvlQl+dF)9sERDbd5Cjt+BaQ zA8EK-y7Hf=PN%_%WG(Rx{)_N(DFaW_du$k|=6nmAVY{Lb3v(5AB%-pc53oowV=&#} zC==+1Y4iM$w>z(Ci387*L)B4e;&0BV~{wEzrq3wRD`GmcitkZGCD#a@+Yg9_TSghQG!1#YMp=7 zHINZCvAKq8wi!R;Y#bwYd+XmEfXI9*X93b?LY#q^DqO?kHDQDCi=Drnu|>+@RSK%h zG_$dS2bgRxrzsXS60EO)fHUOUUOCMcFhn;8j=6`zO-^u*hpl2aj}1G4RYMf6eD{5I z0fZP5?HDx2C5(7GNdf)6zilN)1SPar2x@m4`7k2%|IjCj15r)-U!-8b^M_UP8i8b> z&tnr%oX9G2=X@ zg!%#vK+lUfpXthVp{xJULF5vuTEN5HwoDrx4Gs1(SgQ%J2~@9~}&o z$nz011tGQ|f#YcnM!bS@$Ok-P|JhZLuj3feSueeZQ z3WM5)G{G4jU3;jid_PAtZO_8bc;(ItT^Nu^sZvc*j)iwEAMGfbDxjux|7@o4=7J$J zK~3gg?@dxz>Dt4cYvI; zZ{}j11Pzw$-*}WZln)?~MG4*HZV_8Qz9Rl6?lD>vbkVEFT1w0Y-rw|=U;{g>O@vnV z#EWc_FpR>1vvJ|;%}u4sh7m&7-{bq+$x<(i|9q8Td=!CpY>{83eNvEf?J-pZ{`jn6 z#@Y5315qe$AIVim*kE(vG}x@uBDVo$quTAMH!lw7TiL_FOP?8GHgeE*bgMMRfwvsf zo2M*ks5H;wEl2#JN0&W2^h+43%|;QS#Z6d`{Q71oqv|dl9w_Qfj!_`n*J*UPg5hv4 zL%`C=u=0`pedSAi-~AX8X-Qa9{ z*?*fW%)|Bk+#_dx`WGp;&%tQN!%FQgbcZYLExOCCeI0$J6L3w6XYYJ5C*j&d=35^L z-)o~OxI_~o9#Fb?^TojrqKL=y2ElJX zr96bc;l_Nhkvi^_aEZG(YV)me@|;lJ7OsH$z%u`-JkCGT)vlJfmuB zeH@`ZnP;w*S}Rwq$kCu$`inXQEj^)lJ?lz45gF~#fLtd7dhhU|Y^iK)u$>B1j&94u zs_uz-U};eO_=~7SCeBv3-1zBKA>XSlNMBTl;vy_IERhesR$2xrWCkwbCjYL@ z)x0OK?E5vCqehyph5ApGZR}>n*tj-?zN8SvNpO;F{gKI(Qv;dmmTSFSr{W}SN|zP* zmIQ-o>OG8QfBnGaxD-#F#9FrYif#J##3RAXkd34f%?gy+!`}Iv3sh5ER@2Qr{bqmA z>ZN)vdHZ@PatJ;~$G%e4+BNIte#U*IXwq0Vx>21sC)^4z6 z>zk3{b}$zv)D)je*OWkT&MFJknU26mT^Lhw zwE6;j_ALfRCc?nq$P_?^xDlJ0dQufr zw14-Xt@oD^77@m91e|@Y{ALk_<6YH@ZS;jx1~rWAhjl8@K&jc_K2Y|x7f--YNiKr! zednVXfDh))j?j$TcOoz#uE=Stl9WiWfk~`N;0{ztfoxBnDRnD2j}^?)e=lR8A@2Gb z$)mbYIMxu%xh7C9#lzT}`Fn}d#W5+$ zr)5DRDC)rl@vBd__kZ?*BDAKxrb#p_tBN%DH7t> zF_NqbL;OXD)0phZQjP);k^(|gyqSiSnDAk6u*VF<~svosbR z#nVk?ch9)X5xMTLVAfjq#n941l4)plD6z=FBDS6m?Q-riPZ$!5mw$E9sXR{g8Kn3D zy1y`NDK#M9<-j?6xADq~2(84-@3i5Af)6>Nz1~n4-}>X6XzNj(dZG&gJcuPz7|KKb zxEv!tlpu{W3=nRL*(V)(*zAgy4$7$w^r>@M+BNQq9`Y;APxuYNnIm3|UH256HyC{> zjazfic~2F2hlS8F=qVBF#o+la6eWy1PR|+37y}*!@>AGw{Ep9tjSNQ>Ff)z$ln-Lj zrqqOmFHdWq?%HiVrNos|MYbuLo|6^)<`?Rc;RKyrWcmJp*(uY0IX|`Pl9w$LwW73L z(Dt(@OG0P!Cnxld?wTaIp5qr@sxh|LlO*tPfgSbNgIJ#+smr^@J@Blubr@_v0+k%3 zG_Bn_I2QCvd${yC$n8sdfy;!c+2tycPqO~|(8yRc$BJg7wynR5RjTHAL2|D`3a^ z3qy_fJS1yq#*=*`Mt~?-TunOz_`1Kr&fPH3OyC1f+*dQg@PRw=!3rQ4=f)7m}> z3qYtlAd%&^eCeKh;dTLHbut@HraS(>ULtt4!cfOwUk5Io+*a#9uqc>V$vGg;7bONG@P&J)UlRAA+U{ID?1U@7aa_^IW;5mf zhQ>|pk(K<^;#~?dB=TKk(~`8Z;9Lg@iH3@faxvz1`2PUTbtX>$ literal 0 HcmV?d00001 diff --git a/images/cursor.svg b/images/cursor.svg deleted file mode 100644 index 5a0ab87dbb..0000000000 --- a/images/cursor.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/gamejolt.png b/images/gamejolt.png new file mode 100644 index 0000000000000000000000000000000000000000..d72c1540549d5a3d19cff91b8626df86368c5777 GIT binary patch literal 1926 zcmah~c{E%39=|whElM$i8EdFSLakLXh9Q?@&{4Am_#5dai=_8+l6%EJf<{4~i0m*hu@N=hXr zL;|U)sVLHAa$-1<8i}GLM3=0hHJ~t(-sdj3K+akkx(2#%m>vSAZ(_J_NFxKtP^Vy! znVyQn8ylJ$8=4tYh;XCR@c3|eLIgZ90+ASrNRBeO;Dbb1ApN|NS4hY!vB>mTRA!v% zHOgtim#4EYS>y#4B}lH37E&B zm}VlTCDyei%uip7$xme!E!9XE$wQYt8AF(l)XDbl_-TXPw9iRF8r5X-p6G19 zrk$pCi%#e9T7al)LX%`W;iTngbWll6S`Gq~)F42|1OmQzsr~fVFx~GDLcH9HD-ff>2bN#~%`CG=+tlNLf$@JAM z4-UEeYM!0HkQQSnca*iJQ2Q&ntAQ_g85*oFEZ6?^NC+01yH*umiXw8%6Mk)idYP9e8?lz^nsZN(i&V9+thYO%@S~oY zvddAc>?d>=lQNNm^~tfb@=f~wa1%Y-7lnAdwFE@Vcf)PToTPv)f1D2ULE6v%#taJn zSfYa!u|zuI#3GD%L{zgpISJQK*D@jU85&@ld(l$#9hd=BHjkvo(WPt~wZ z>w3dh8I(AjZJ4{_!0-e`j9AyBb2`j%9&GJ~^^IwAdL~Y)rO;Ia=4mK4`?@6iB4a2~ z(zXz*swQ2q^SvaElb>}m_}zKj$xSm>1Oc}&y4#h-l>Khf=)Udu!%F@y!Q@Z|{h zSyTva<=C3y;?B~nUsBy0CUwM|S)YsDpwaEtAcByw)kMSwUwB8;MqBnpM^X^{cf!Pj=Iv}JPdAtx%LZdBM+UjlwXI`2=mBN6 zh@YuWZMI;sw#Z!T)$x~BE1%t(R`}Cr!|L+={)L>`Qm^#Tj$7fq9^6mocty#%+c;@* z$7bH6<-)}&^cjb(G|?tvT^d20$=^^iY+q=S5`$E zT`f*$Dh_V&Csk1#gN&k)8}>z@p6!P|YxVtmjU2yB?I#l(CZx#h8oH?jZ*Q>Of}PLj zmINeaY>(xGETI8wUXe)btzo1@`GWF-+*#N1Tdw84d0*#p8{RS}N$1Pf&QIP;@miFTBffkErdtKs^IinC-Ccfh7rcl-^9YUqsBhYR zDsZY5-V2!x{wPjf-3;QDmX>e4TjM$$w~hDFV?KSYl}SywDijRaYadEf{+|=uA>S@a zc`8EtwJ%zTVHJP*vdq2*8zoJcPGx_2_f9{DK6{wY3jP<^{-~A4TJMM|jX!CC^sJ^p zy>9G@h5Cl3KeIO+-4jWxa1IjMlDV6!F`e*)=)cGdt5 \ No newline at end of file diff --git a/images/pointerlock.png b/images/pointerlock.png new file mode 100644 index 0000000000000000000000000000000000000000..e653ce69e45e5c8ce89cf5af909b56b1e77db941 GIT binary patch literal 28312 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

N$J@zI$Ad%d2{wM9acet7gN|2J* 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 \ No newline at end of file From ff2580601f5c777e74ed8f969cf0c0a2fea041eb Mon Sep 17 00:00:00 2001 From: Alestore Inc <82514000+Alestore@users.noreply.github.com> Date: Sun, 9 Jul 2023 00:52:47 +0200 Subject: [PATCH 4/8] Add Alestore/nfcwarp extension (#628) --- extensions/Alestore/nfcwarp.js | 73 ++++++++++++++++++++++++++++++++++ website/index.ejs | 6 +++ 2 files changed, 79 insertions(+) create mode 100644 extensions/Alestore/nfcwarp.js diff --git a/extensions/Alestore/nfcwarp.js b/extensions/Alestore/nfcwarp.js new file mode 100644 index 0000000000..c731f04095 --- /dev/null +++ b/extensions/Alestore/nfcwarp.js @@ -0,0 +1,73 @@ +(function(Scratch) { + 'use strict'; + + /* globals NDEFReader */ + + const extIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAACXBIWXMAAAsTAAALEwEAmpwYAAACN0lEQVR4nK2WzW7TQBDHDRIVHCr6CYV+PUG5hENvlpKdfyxX6q0SanmVqo+AkKqqPAG8CAVE1RJaKYn6cSiiIO70RBnYydi4ttcJjiPtIbsz/59nPZ4Zz9MfEz1nog8MXDHAhYvoGxPtMDAvvrXaHQZeJ2ysxnsGNiL9HgR4lRK6YOB8AOAPNmZJNJaX76lf2m73XyTZwwM2ZoGBswFgLfa8W6q16bBb9zTEDEgjnWei074wgMTemKeOh9nzHO9EQOIcBHNMdNInqheJ67vOOf/pOZxjkAjU67MMdAtAe4mkusyzKQTx6uooAxN6LY+ZqOMAXSYSq/v/oDBclMRoNCblf7P5iInaOaBrm+IKOiwLskKf2Pen9GoeMHCU8THmvoIOyoMGgdXrD6sBRd+MC2bMwvAg+y0RHcewIJjW1J+OsywMF6uIaF9Egc8Ka3MYzqjwfqWgRAStGGazsFKQvZ6b19XS/eO4Hg4F6hXWaO/IJoDs+/6UZGHSZ8iIZlJZ17EVQs5WVsYZ+FgNqCfGTpjvj8WwkqBDcVpbG2Hgdw6sbRNBbBqNSREvBSLqJIrkd5cNR5EBE7YAl4noawKU1xhZV9e2kNRY4ARlGx/RL/b9u+r4sgDE0hSDYK4QpI3vnUOkpineLARBS1Q0EeWD3tqDDYfzpjhubd2OS0/xOtPvLg/0LAp3N+fwi50BtBo8kdGqP+w8M3IR7aRnu3Xb+2+8M6I3cee0Qwqw7ZoJUutKtKJI/gr8AfOqgU5hKhA4AAAAAElFTkSuQmCC'; + const blocksIcon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMCIgd2lkdGg9IjE2MDAuMDAwMDAwcHQiIGhlaWdodD0iMTYwMC4wMDAwMDBwdCIgdmlld0JveD0iMCAwIDE2MDAuMDAwMDAwIDE2MDAuMDAwMDAwIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0Ij4KPG1ldGFkYXRhIGZpbGw9IiNmZmZmZmYiPgpDcmVhdGVkIGJ5IHBvdHJhY2UgMS4xNSwgd3JpdHRlbiBieSBQZXRlciBTZWxpbmdlciAyMDAxLTIwMTcKPC9tZXRhZGF0YT4KPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsMTYwMC4wMDAwMDApIHNjYWxlKDAuMTAwMDAwLC0wLjEwMDAwMCkiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSI+CjxwYXRoIGQ9Ik0yNjk3IDE1OTg5IGMtNTY1IC01MCAtMTEwOCAtMjY0IC0xNTY3IC02MTkgLTExNCAtODggLTM5MSAtMzYyIC00ODQgLTQ4MCAtMTY0IC0yMDYgLTM0MCAtNTA5IC00MzQgLTc0NSAtODQgLTIxMSAtMTQzIC00MzAgLTE4NCAtNjgwIGwtMjMgLTE0MCAtMyAtNTEwNSBjLTIgLTM3MDkgMCAtNTE0NSA4IC01MjUwIDcwIC05MDUgNTQ5IC0xNzI0IDEzMDQgLTIyMjkgMzU3IC0yMzkgNzc4IC00MDIgMTIwMyAtNDY2IDIwOSAtMzIgNDA0IC0zNiAxNDM4IC0zMyBsMTAzMCAzIC01MCAyOSBjLTQ3MyAyNzIgLTkwMCA5ODAgLTExMzUgMTg4MCAtMTM2IDUyMSAtMjAwIDk1MiAtMjYyIDE3NjYgLTkgMTE2IC0xMyAxNTYzIC0xNSA1NzE5IGwtMyA1NTY0IDU5IC01NCBjMzMgLTMwIDE0NTAgLTE0MzMgMzE1MCAtMzExOSBsMzA5MSAtMzA2NSAwIC05NjAgMCAtOTYwIC0xNjcgMTY2IGMtMjc2IDI3MiAtMzY2MiAzNjM3IC00Mjg4IDQyNjEgbC01ODAgNTc4IC0zIC0zMDI4IGMtMyAtMzA1NiAwIC0zMzg3IDM0IC0zOTU3IDc2IC0xMjg5IDI1NyAtMjI1MSA1NTggLTI5NjggNTggLTEzOCAxOTUgLTQwNCAyNzEgLTUyNyAxNTYgLTI1MSA0MzQgLTU2MCA2NDggLTcxOSAzNTcgLTI2NiA3NzkgLTQ0OSAxMzIwIC01NzEgbDE3NyAtNDEgMjYzMyA0IGMyODk0IDMgMjY2NyAtMiAyOTgzIDYyIDk2MSAxOTQgMTc4NyA4OTMgMjE0OCAxODE2IDg2IDIyMSAxNDAgNDMwIDE4MyA3MDkgMTYgMTA4IDE4IDQxMyAyMSA1MTg1IDIgMzQ1NCAwIDUxMTcgLTggNTIxNyAtMTkgMjc4IC02MSA0OTAgLTE0NCA3NDMgLTM3NCAxMTI2IC0xMzc3IDE5MTQgLTI1NjEgMjAxNSAtNzIgNiAtNTU1IDEwIC0xMjAwIDEwIGwtMTA4MCAwIDU4IC0zMyBjMTAwIC01NiAxNzkgLTExOSAyOTcgLTIzNyA0NjUgLTQ2MyA4MDggLTEyNzMgOTc5IC0yMzEwIDU0IC0zMjkgODkgLTY1NCAxMjMgLTExNDUgOCAtMTI1IDEyIC0xNjI3IDE1IC01NzA0IGw0IC01NTMzIC0zOSAzMyBjLTIyIDE5IC0xMDc0IDEwNjAgLTIzMzggMjMxNCAtMTI2NCAxMjU0IC0yNjY1IDI2NDIgLTMxMTEgMzA4NSBsLTgxMyA4MDUgMCA5NjQgMCA5NjMgMTg1MyAtMTg0MyBjMTAxOCAtMTAxNCAyMTUyIC0yMTQzIDI1MjAgLTI1MDggbDY2NyAtNjY1IDAgMzAyNSBjMCAxNzQ5IC00IDMxNTMgLTEwIDMzMjkgLTU3IDE3OTQgLTI3NCAyOTkyIC02OTUgMzgzOCAtMTUzIDMwOCAtMzExIDUzNiAtNTI1IDc1NiAtMjIxIDIyNyAtNDQxIDM4NiAtNzM1IDUzMSAtMjY2IDEzMSAtNTM2IDIyMyAtODgzIDMwMSBsLTE1NCAzNCAtMjU5NiAtMSBjLTE0MjkgLTEgLTI2MzYgLTUgLTI2ODUgLTEweiIgZmlsbD0iI2ZmZmZmZiIvPgo8L2c+Cjwvc3ZnPg=='; + + class NFCWarp { + getInfo() { + return { + id: 'alestorenfc', + name: 'NFCWarp', + color1: '#FF4646', + color2: '#FF0000', + color3: '#990033', + menuIconURI: extIcon, + blockIconURI: blocksIcon, + blocks: [ + { + blockType: Scratch.BlockType.LABEL, + text: 'Only works in Chrome on Android' + }, + { + opcode: 'supported', + blockType: Scratch.BlockType.BOOLEAN, + text: 'NFC supported?' + }, + { + opcode: 'nfcRead', + blockType: Scratch.BlockType.REPORTER, + text: 'read NFC tag', + disableMonitor: true + } + ] + }; + } + + supported () { + return typeof NDEFReader !== 'undefined'; + } + + nfcRead() { + if (!this.supported()) { + return 'NFC not supported'; + } + return new Promise((resolve, reject) => { + const ndef = new NDEFReader(); + ndef.scan() + .then(() => { + ndef.onreadingerror = event => { + console.log('Reading error', event); + resolve('Tag not supported'); + }; + ndef.onreading = evt => { + const decoder = new TextDecoder(); + const record = evt.message.records[0]; + console.log('Record type: ' + record.recordType); + console.log('Record encoding: ' + record.encoding); + console.log('Record data: ' + decoder.decode(record.data)); + resolve(decoder.decode(record.data)); + }; + }) + .catch(error => { + console.log('Scan error', error); + resolve(`Error: ${error}`); + }); + }); + } + } + + Scratch.extensions.register(new NFCWarp()); +})(Scratch); diff --git a/website/index.ejs b/website/index.ejs index f6dd5b3ab3..013f65559a 100644 --- a/website/index.ejs +++ b/website/index.ejs @@ -710,6 +710,12 @@

Allows you to use webhooks. Created by CubesterYT.

+
+ <%- banner('Alestore/nfcwarp') %> +

NFCWarp

+

Allows reading data from NFC (NDEF) devices. Only works in Chrome on Android. Created by Alestore Games.

+
+
<%- banner('itchio') %>

itch.io

From 13e9166ddee1129a6952a92f20cddaf46147d0c8 Mon Sep 17 00:00:00 2001 From: NexusKitten <127152751+NexusKitten@users.noreply.github.com> Date: Sat, 8 Jul 2023 21:28:37 -0400 Subject: [PATCH 5/8] Add clipboard extension (#667) --- extensions/clipboard.js | 118 ++++++++++++++++++++++++++++++++++++++++ images/README.md | 3 + images/clipboard.svg | 1 + website/index.ejs | 6 ++ 4 files changed, 128 insertions(+) create mode 100644 extensions/clipboard.js create mode 100644 images/clipboard.svg diff --git a/extensions/clipboard.js b/extensions/clipboard.js new file mode 100644 index 0000000000..7064a0194f --- /dev/null +++ b/extensions/clipboard.js @@ -0,0 +1,118 @@ +/*! + * Copyright 2023 tomyo-code + AdamMady + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function(Scratch) { + 'use strict'; + + if (!Scratch.extensions.unsandboxed) { + throw new Error('Clipboard must run unsandboxed'); + } + + const extensionicon = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4MC40NTQ1NCIgaGVpZ2h0PSI4MC40NTQ1NCIgdmlld0JveD0iMCwwLDgwLjQ1NDU0LDgwLjQ1NDU0Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTk5Ljc3MjcyLC0xMzkuNzcyNzIpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSJub25lIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtZGFzaGFycmF5PSIiIHN0cm9rZS1kYXNob2Zmc2V0PSIwIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6IG5vcm1hbCI+PHBhdGggZD0iTTE5OS43NzI3MywxODBjMCwtMjIuMjE2OSAxOC4wMTAzNywtNDAuMjI3MjcgNDAuMjI3MjcsLTQwLjIyNzI3YzIyLjIxNjksMCA0MC4yMjcyNywxOC4wMTAzNyA0MC4yMjcyNyw0MC4yMjcyN2MwLDIyLjIxNjkgLTE4LjAxMDM3LDQwLjIyNzI3IC00MC4yMjcyNyw0MC4yMjcyN2MtMjIuMjE2OSwwIC00MC4yMjcyNywtMTguMDEwMzcgLTQwLjIyNzI3LC00MC4yMjcyN3oiIGZpbGw9IiMwMDgwODAiIHN0cm9rZS13aWR0aD0iMCIvPjxpbWFnZSB4PSI0MzQiIHk9IjMwMCIgdHJhbnNmb3JtPSJzY2FsZSgwLjUsMC41KSIgd2lkdGg9Ijk0IiBoZWlnaHQ9IjExOCIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFGNEFBQUIyQ0FZQUFBQkJMU1ExQUFBQUFYTlNSMElBcnM0YzZRQUFCckpKUkVGVWVGN3RuVnZJYmtNWXgyZTJuTUlPeVNHbDVCQjJTWExNc1lRTFo5cHNaMEl1aEhKQmlkeTZJaUVrNTFPT0VYZkVqZHk0c0pPemN0Z1hLRGtrNStTdmI3Ny9zMzNmM3U5YTYxbnZtdlhNdk85KzNwdXA5VDd6UERPLythOVpzMmF0bVJWRDVUOEFlN0tJMXpNOWx1bTJUTDlqK2dyVGV4ZlNHT09mTlZjdDFseTRoYkk1ZU9NV0FuQXpROTdLZEN0bEVlUU1XRTNsdjYzTVoycFdyZUlkdktrT1V0ZHlHME5LT3EwNHBJOVAxNFFZNDd2R1ZXa05OMjJsUnF1RGd4OE43V1RIQVBibFB4OHczVHhURVQ2bm4vMm8vSDh6K1Iza3BockZiN0xnQVd6QkpyeUo2UWxNdHh6VXRQOW5mcHFLdTN1U1B3Q1A4dmlsSGZIKzR2OC9NZDJaNllxR2ZPRHhreG4vOVliNGovRzRuSGxEcXkzbGU0SnhuMW5xY0wzaUhUeHN3UVBZbmkwaFYvMjloeloxUS80MzJQSW5OaWp1TXg3ZnB5SC9iengrTVAwa2V3RFg4TGljU1UzZFovby94bmhkUS94ZmVIeTd6UFdYTSs0cHhyODRwUTUrRVRNQWMvRFM5NnpKM05JYnVudVZMWDU2ZytLKzVmRmRHOHFSenNnWTQyRU4rZi9nOGFZNzNPZVkvN3lHL0QvdytJNGpjemhWRk8vZ0Z4VnZEcjVMS2JrRWNCa1ZKeGV4Wlg0QnlCekxMZzBCcFp4SDBjOTc3Q0p1cFAzdFRKdjYrT2VaNzl3R3hiL0c0NmZrcW5DRG4zV2llQWUvcUhoejhITFY3V3JvZjJnZzQrZ3VlMm5RQjZpMFc5b3lBT2pxNHlXN2xFTXVoanQwS0YzeWRmWHhLMm1ZN0VJSVJ6TGRyS09pY29adHJTeEhNbHNZMVRqNFJjVlhCLzVIdHVReFREL3Bram9WM210T0JNRDM5THVUeHY4VU51a0pWWXp4ekQ1NUFUVGRFWXNiK2Y4U0huaVFhV3MramVJZGZIdExqUVkrRFRkampCZjBVWXJXRnNCcHRIMVpveFN0M3dsMklxQzlXSitmQi9ocXpLbzljeldLZC9BOVdpZ24rTWVwa0s1WlExWHhBSnhFdzZ1WW5zRTAxL3g3Vnpua1J1bGhHcVpaMFJqalIxMFpOZjhyN2tlU0c0M2lIYnlHT0cxeWduK1Npa2l6YW4xL0FPUk84SDdtM1oxcExROWg1TDVBWm1mUFlYM2x2cUpYbFIyOEh0ZDhnUWR3Tk92K3BuRWZya2MrMlRMTnBZUVFWbEg1di9aeFdGenhEajQwVGZhcEw2NVQ5ZkVBWkpTd2Z4L0ZWR1I3SnhWL1E1OHkxYUI0QjkvU1lwcmhaQy9GQXppQThkNW4yalc3MTBkUWxyYmZVUEV5Q2xQRkxxWjRCOS81UUdlY1BuN0pVLzk3VkJLcDEwaUdtWHYwR2RlWFZMeThidUhnQy9YeHZlYTlLeFMrUEVGN2lJcVhKMTZ0UlMycGVMbTRPbmhMeFZlb1hOTWlGVk84YVMwckRPYmdDeldLZzNmd2hRZ1VDdXVLbjNmd0FPVFo2ZVhHZGIyTDQrdG5qZVBXTVk1MzhNdmJ3YXlyQVpEZWV3OGhwUGUrRFgvcHJlTVlZM29MdVphZmd5L1VFcGJnWlUyUjlQVldWYjZEaW4vRUtxQW1qb1BYVUJyQnhnejhDR1dmYVpjT3ZsRHo1UVF2NnpNdktsU1htUXJyNEFzMWw0TjM4SVVJRkFwcnBuZ0FCN0tPRTFkY0Y2cC9qckN5dzlOTHZGLzRYZVBVd1dzb3RkdFVELzVGbHYvczRYV3R5b01zUTVYZFF0WnFTcWRkcjZ0NWhhOTFPQW5Bd1M5cEVVdndhZVYyQ01GNlBsNGp3Q0UyZnkrOWRtblhTRG40SWNnWDgxWVBYdmI0emIyejBYQjB3enpJeXZTMDRqekdxRnFwYnFsNEIxK2lqeDhtcXZuTGJhYjQrVU0zckVZT2ZoaS9xWE03K0tuUkRjdG9CbjdKUnFHeVUrdXdrbytYTzYzd0dQdExDZzUrNHdhY08vQ3l3K21WNDRrMWkrY1BxZmhEc25ocmNHS3BlQWRmWWh3UElNMVhoeERPR2xOSkdYeW5mUzFqakx0bDhOWG93bEx4RHI2UTRnOW4zT1BHVkZJRzMxOVE4UzlrOEZXRjRoMThDY1dQcVo1WjlHM1d4ODhpbkRITDdPREhwTnZpMjhIUEFmaFJOL3dzeEdlMHNEa1Y3K0I3TkpNWmVBQlhzMXhWclVWU3NQcUs0L3J6RmJacUV3ZmZqV3Jtd1pkYTlkZU50dDBpdmFJWFk1UXZIUXoxbC9KYkt0N0JqM1RuMm5weEJYQXQ0MTZSUlRKMlRyNms0clBPcWxvcTNzR1hVTHlkUUdjamtwbmlad09IWFNrZHZCM3JaWkVjdklNdlJLQlFXRmY4dklNSGNCRHJlRVNodWtyWVR6a3VmNnRrT2N3VTcrQ1hON01sK0ZvV24zMU14Y3NXdTBXRTcrQ0xZTGVkSkx1dmtybWFkNmo0NHdzeE41K2RkUEFsNW1vQXlGZmhaUkZhS2NISi9IcXY3emJsTHF4bEgrL2dTeWcrdDJKbTNaK1o0bWNkVk83eU8vamNSSlgrSEx3U1ZHNHpCNSticU5LZmcxZUN5bTJXRTN6YW56M0d1Q1ozSWVmUlg4NDl5Ung4RDRYa0JKLzJhd2toSEVybGY5MmpISnVNS1lEVnJHeDZEeW1FMFBwVlQ4MmVaQTVlSVo4eHdFdFkyU3BLdm9HbktFNVZKbkdrMG9qZmJlaC9oU2FPUnZFT3ZwM2sxT0JGd1RMWnBXa3d0NW1ld0xwMHJRVGc0S2VIT0UzTzllRFRON2xEQ0JkTzQ4WHpxQW5JenEzcDYwRUxpbmZ3YW5hREREY0N2NUx1MGpQTEVNS3FRZTQ5ODRZRUJMaDhDVGw5UFdoQjhRNStYTEZNQlA4ZjVqR04yQ3N0cTkwQUFBQUFTVVZPUks1Q1lJST0iIGZpbGw9Im5vbmUiIHN0cm9rZS13aWR0aD0iMC41Ii8+PC9nPjwvZz48L3N2Zz4="; + + let lastPastedText = ''; + + window.addEventListener('copy', (event) => { + Scratch.vm.runtime.startHats('clipboard_whenCopied') ; + }); + window.addEventListener('paste', (event) => { + Scratch.vm.runtime.startHats('clipboard_whenPasted'); + const clipboardData = event.clipboardData || window.clipboardData; + const pastedText = clipboardData.getData('Text'); + lastPastedText = pastedText; + }); + + class Clipboard { + getInfo() { + return { + id: 'clipboard', + name: 'Clipboard', + blockIconURI: extensionicon, + color1: '#008080', + color2: '#006666', + blocks: [ + { + opcode: 'whenCopied', + blockType: Scratch.BlockType.HAT, + text: 'when something is copied', + isEdgeActivated: false + }, + { + opcode: 'whenPasted', + blockType: Scratch.BlockType.HAT, + text: 'when something is pasted', + isEdgeActivated: false + }, + '---', + { + opcode: 'setClipboard', + blockType: Scratch.BlockType.COMMAND, + text: 'copy to clipboard: [TEXT]', + arguments: { + TEXT: { + type: Scratch.ArgumentType.STRING + } + } + }, + { + opcode: 'resetClipboard', + blockType: Scratch.BlockType.COMMAND, + text: 'reset clipboard' + }, + '---', + { + opcode: 'clipboard', + blockType: Scratch.BlockType.REPORTER, + text: 'clipboard', + disableMonitor: true + }, + { + opcode: 'getLastPastedText', + blockType: Scratch.BlockType.REPORTER, + text: 'last pasted text', + disableMonitor: true + } + ], + }; + } + + setClipboard(args) { + navigator.clipboard.writeText(args.TEXT); + } + + resetClipboard() { + navigator.clipboard.writeText(''); + } + + clipboard() { + if (navigator.clipboard && navigator.clipboard.readText) { + return Scratch.canReadClipboard().then(allowed => { + if (allowed) { + return navigator.clipboard.readText(); + } + return ''; + }); + } + return ''; + } + + getLastPastedText() { + return lastPastedText; + } + } + + Scratch.extensions.register(new Clipboard()); +})(Scratch); diff --git a/images/README.md b/images/README.md index 9b629d4eb8..76bd6f0da2 100644 --- a/images/README.md +++ b/images/README.md @@ -233,3 +233,6 @@ All images in this folder are licensed under the [GNU General Public License ver ## Lily/LooksPlus.svg - Created by [@LilyMakesThings](https://github.com/LilyMakesThings) in https://github.com/TurboWarp/extensions/pull/656 + +## clipboard.svg + - Created by [@AdamMady](https://github.com/AdamMady/) diff --git a/images/clipboard.svg b/images/clipboard.svg new file mode 100644 index 0000000000..f02be5a0ee --- /dev/null +++ b/images/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/index.ejs b/website/index.ejs index 013f65559a..fd3812c909 100644 --- a/website/index.ejs +++ b/website/index.ejs @@ -476,6 +476,12 @@

Clipping outside of a specified rectangular area and additive color blending. Created by Vadik1.

+
+ <%- banner('clipboard') %> +

Clipboard

+

Read and write from the system clipboard.

+
+
<%- banner('penplus') %>

Pen Plus

From e19128c53e682f6768410b9b182f0a39a2b2ea7a Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Sat, 8 Jul 2023 21:11:10 -0500 Subject: [PATCH 6/8] Generate a sitemap (#712) --- development/builder.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/development/builder.js b/development/builder.js index 9a2f025994..38330bafb5 100644 --- a/development/builder.js +++ b/development/builder.js @@ -105,6 +105,39 @@ class SVGFile extends ImageFile { } } +class SitemapFile extends DiskFile { + constructor (build) { + super(null); + this.getDiskPath = null; + this.build = build; + } + + getType () { + return '.xml'; + } + + read () { + let xml = ''; + xml += '\n'; + xml += '\n'; + + xml += Object.keys(this.build.files) + .filter(file => file.endsWith('.html')) + .map(file => file.replace('index.html', '').replace('.html', '')) + .sort((a, b) => { + if (a.length < b.length) return -1; + if (a.length > b.length) return 1; + return a - b; + }) + .map(path => `https://extensions.turbowarp.org${path}`) + .map(absoluteURL => `${absoluteURL}`) + .join('\n'); + + xml += '\n'; + return xml; + } +} + const IMAGE_FORMATS = new Map(); IMAGE_FORMATS.set('.png', ImageFile); IMAGE_FORMATS.set('.jpg', ImageFile); @@ -116,7 +149,7 @@ class Build { } getFile (path) { - return this.files[path] || this.files[`${path}index.html`] || null; + return this.files[path] || this.files[`${path}.html`] || this.files[`${path}index.html`] || null; } export (root) { @@ -192,6 +225,8 @@ class Builder { build.files[oldPath] = build.files[newPath]; } + build.files['/sitemap.xml'] = new SitemapFile(build); + const mostRecentExtensions = extensionFiles .sort((a, b) => b.getLastModified() - a.getLastModified()) .slice(0, 5) From cd85f6332c65a732e937fb3b9351a9c50cc816ba Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Sat, 8 Jul 2023 21:19:15 -0500 Subject: [PATCH 7/8] Don't output sitemap in desktop builds (#713) --- development/builder.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/development/builder.js b/development/builder.js index 38330bafb5..3d755fd631 100644 --- a/development/builder.js +++ b/development/builder.js @@ -225,7 +225,9 @@ class Builder { build.files[oldPath] = build.files[newPath]; } - build.files['/sitemap.xml'] = new SitemapFile(build); + if (this.mode !== 'desktop') { + build.files['/sitemap.xml'] = new SitemapFile(build); + } const mostRecentExtensions = extensionFiles .sort((a, b) => b.getLastModified() - a.getLastModified()) From c0b8f2db73ab395164a2872cb5d42694cbc81937 Mon Sep 17 00:00:00 2001 From: LilyMakesThings <127533508+LilyMakesThings@users.noreply.github.com> Date: Mon, 10 Jul 2023 03:24:14 +0100 Subject: [PATCH 8/8] Lily/TempVariables2: remove console.log (#717) --- extensions/Lily/TempVariables2.js | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/Lily/TempVariables2.js b/extensions/Lily/TempVariables2.js index ad131fbc18..13912281f8 100644 --- a/extensions/Lily/TempVariables2.js +++ b/extensions/Lily/TempVariables2.js @@ -14,7 +14,6 @@ }); function resetRuntimeVariables() { - console.log('runtime variables cleared'); runtimeVariables = Object.create(null); }