Skip to content

Commit e572a32

Browse files
authored
Playground unicode + gzip (#750)
1 parent 9918285 commit e572a32

File tree

1 file changed

+63
-12
lines changed

1 file changed

+63
-12
lines changed

playground/public/js/main_js.mjs

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,62 @@ let boilerplateSrc;
242242
if (boilerplate) {
243243
boilerplateSrc = await fetch(boilerplate).then((p) => p.text());
244244
}
245-
let src = urlParams.get('src');
245+
246+
function base64ToBytes(b64) {
247+
const bin = atob(b64);
248+
return Uint8Array.from(bin, c => c.charCodeAt(0));
249+
}
250+
251+
function base64ToUtf8(b64) {
252+
const bytes = base64ToBytes(b64);
253+
return new TextDecoder().decode(bytes);
254+
}
255+
256+
function bytesToBase64(bytes) {
257+
let binary = '';
258+
const len = bytes.length;
259+
for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);
260+
return btoa(binary);
261+
}
262+
263+
async function gzipUtf8ToBytes(str) {
264+
const encoder = new TextEncoder();
265+
const data = encoder.encode(str);
266+
const cs = new CompressionStream('gzip');
267+
const compressedStream = new Response(data).body.pipeThrough(cs);
268+
const compressedArrayBuffer = await new Response(compressedStream).arrayBuffer();
269+
return new Uint8Array(compressedArrayBuffer);
270+
}
271+
272+
async function gunzipBytesToUtf8(uint8arr) {
273+
const ds = new DecompressionStream('gzip');
274+
const decompressedStream = new Blob([uint8arr]).stream().pipeThrough(ds);
275+
const decompressedArrayBuffer = await new Response(decompressedStream).arrayBuffer();
276+
return new TextDecoder().decode(decompressedArrayBuffer);
277+
}
278+
279+
async function zipCode(code) {
280+
const zippedBytes = await gzipUtf8ToBytes(code);
281+
const base64 = bytesToBase64(zippedBytes);
282+
return 'gzip:' + base64;
283+
}
284+
285+
let src = urlParams.get('src'), isGzip = false;
286+
246287
if (src) {
247288
if (/http(s)?:\/\/.*/.test(src)) {
248289
src = await fetch(src).then((p) => p.text());
249290
} else {
250-
src = atob(src);
291+
if (src.startsWith('gzip:')) {
292+
isGzip = true;
293+
src = src.substring(5);
294+
}
295+
if (isGzip) {
296+
const bytes = base64ToBytes(src);
297+
src = await gunzipBytesToUtf8(bytes);
298+
} else {
299+
src = base64ToUtf8(src);
300+
}
251301
}
252302
doc = src;
253303
} else {
@@ -279,35 +329,36 @@ window.compile = () => {
279329
code = (boilerplateSrc || '') + '\n\n' + code;
280330
evalCode(code);
281331
};
282-
window.share = () => {
283-
let code = editor.state.doc.toString().trim();
284-
code = btoa(code);
285-
url.searchParams.set('src', code);
332+
333+
window.share = async () => {
334+
const code = editor.state.doc.toString().trim();
335+
const src = await zipCode(code);
336+
url.searchParams.set('src', src);
286337
window.location = url;
287338
};
288-
window.blankAOC = () => {
289-
const code = btoa(aocDoc);
339+
window.blankAOC = async () => {
340+
const code = await zipCode(aocDoc);
290341
const url = new URL(window.location);
291342
url.searchParams.set('src', code);
292343
url.searchParams.set('boilerplate', aocBoilerplateUrl);
293344
url.searchParams.set('repl', true);
294345

295346
window.location = url;
296-
}
347+
};
297348

298349
window.changeREPL = (target) => {
299350
document.getElementById('result').innerText = '';
300351
if (target.checked) {
301352
repl = true;
302-
compile();
353+
window.compile();
303354
} else {
304355
repl = false;
305-
compile();
356+
window.compile();
306357
}
307358
url.searchParams.set('repl', repl);
308359
window.history.replaceState(null, null, url);
309360
};
310361
if (repl) {
311362
document.getElementById('replCheckBox').checked = true;
312363
}
313-
compile();
364+
window.compile();

0 commit comments

Comments
 (0)