Why I made it
I wanted to experiment with javascript: bookmarklets and see how far a small injected script could go on any site by making a simple injectable game.
How it works
Typing javascript: followed by code in the address bar on most browsers causes it to execute that code on the page you’re on. For example, entering javascript:alert("Hello!") in the URI field of this very website should trigger a popup. Saving the script as a bookmarklet makes it quicker to run.
The game uses this idea: it adds a canvas to the page, tracks cursor or touch movement, and moves a paddle based on which half of the screen you’re interacting with. I also included a readable version of the code for revision and the one-liner ready for bookmarking.
Code
Here is the Javascript code in a readable format:
// Create canvas
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.style.position = "absolute";
canvas.style.top = "50px";
canvas.style.left = "0px";
canvas.style.opacity = "0.5";
canvas.style.backgroundColor = "white";
canvas.style.borderColor = "black";
canvas.width = 480;
canvas.height = 320;
var ctx = canvas.getContext('2d');
// Create exit button
var button = document.createElement('button');
document.body.appendChild(button);
button.style.position = "absolute";
button.style.top = "50px";
button.style.left = "480px";
button.style.backgroundColor = "black";
button.style.borderColor = "white";
button.style.width = "50px";
button.style.height = "50px";
button.textContent = "EXIT";
button.style.color = "white";
button.style.opacity = "0.5";
button.addEventListener('click', function () {
document.location.reload();
});
// Ball variables
var ballRadius = 5;
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
// Paddle variables
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width - paddleWidth) / 2;
var paddlespeed = 7;
// Bricks
var brickRowCount = 5;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 15;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
var score = 0;
var lives = 3;
// Draw ball
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
}
// Draw paddle
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = 'grey';
ctx.fill();
ctx.closePath();
}
// Draw bricks
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
var brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
}
}
}
}
// Draw score
function drawScore() {
ctx.font = '16px Arial';
ctx.fillStyle = 'black';
ctx.fillText('Score: ' + score, 8, 20);
}
// Draw lives
function drawLives() {
ctx.font = '16px Arial';
ctx.fillStyle = 'black';
ctx.fillText('Lives: ' + lives, canvas.width - 65, 20);
ctx.font = '20px Arial';
ctx.fillText('Made by Emmanuel Ghattas', 100, 25);
}
// Main draw loop
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
drawLives();
collisionDetection();
// Ball collision with walls
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
} else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
dy = -dy;
} else {
lives--;
if (!lives) {
alert('GAME OVER!\nGame by: Emmanuel Ghattas.\nBye-Bye!');
document.location.reload();
} else {
x = canvas.width / 2;
y = canvas.height - 30;
dy = -dy;
paddleX = (canvas.width - paddleWidth) / 2;
}
}
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
// Collision detection
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (
x > b.x &&
x < b.x + brickWidth &&
y > b.y &&
y < b.y + brickHeight
) {
dy = -dy;
b.status = 0;
score++;
if (score === brickRowCount * brickColumnCount) {
alert('YOU WIN, CONGRATULATIONS!');
lives = 99;
dx = 10;
dy = -10;
paddlespeed += 2;
}
}
}
}
}
}
// Mouse/touch controls
document.addEventListener('click', function (e) {
var screenWidth = window.innerWidth;
var clickX = e.clientX;
if (clickX < screenWidth / 2) {
paddleX -= paddlespeed;
if (paddleX < 0) paddleX = 0;
} else {
paddleX += paddlespeed;
if (paddleX + paddleWidth > canvas.width)
paddleX = canvas.width - paddleWidth;
}
});
document.addEventListener('touchmove', function (e) {
var screenWidth = window.innerWidth;
var touchX = e.touches[0].clientX;
if (touchX < screenWidth / 2) {
paddleX -= paddlespeed;
if (paddleX < 0) paddleX = 0;
} else {
paddleX += paddlespeed;
if (paddleX + paddleWidth > canvas.width)
paddleX = canvas.width - paddleWidth;
}
});
// Start the game
draw();
Here it is in the original, ready-to-bookmark one-liner format:
javascript:%20var%20canvas%20=%20document.createElement('canvas');%20document.body.appendChild(canvas);%20canvas.style.position%20=%20%22absolute%22;%20canvas.style.top%20=%20%2250px%22;%20canvas.style.left%20=%20%220px%22;%20canvas.style.opacity%20=%20%220.5%22;%20canvas.style.backgroundColor%20=%20%22white%22;%20canvas.style.borderColor%20=%20%22black%22;%20canvas.width%20=%20480;%20canvas.height%20=%20320;%20%20var%20ctx%20=%20canvas.getContext('2d');%20%20var%20button%20=%20document.createElement('button');%20document.body.appendChild(button);%20button.style.position%20=%20%22absolute%22;%20button.style.top%20=%20%2250px%22;%20button.style.left%20=%20%22480px%22;%20button.style.backgroundColor%20=%20%22black%22;%20button.style.borderColor%20=%20%22white%22;%20button.style.width%20=%20%2250px%22;%20button.style.height%20=%20%2250px%22;%20button.textContent%20=%20%22EXIT%22;%20button.style.color%20=%20%22white%22;%20button.style.opacity%20=%20%220.5%22;%20button.addEventListener('click',%20function(event)%20%7B%20%20%20%20%20document.location.reload();%20%7D);%20%20var%20ballRadius%20=%205;%20var%20x%20=%20canvas.width%20/%202;%20var%20y%20=%20canvas.height%20-%2030;%20var%20dx%20=%202;%20var%20dy%20=%20-2;%20%20var%20paddleHeight%20=%2010;%20var%20paddleWidth%20=%2075;%20var%20paddleX%20=%20(canvas.width%20-%20paddleWidth)%20/%202;%20var%20paddlespeed%20=%207;%20%20var%20brickRowCount%20=%205;%20var%20brickColumnCount%20=%205;%20var%20brickWidth%20=%2075;%20var%20brickHeight%20=%2015;%20var%20brickPadding%20=%2010;%20var%20brickOffsetTop%20=%2030;%20var%20brickOffsetLeft%20=%2030;%20var%20bricks%20=%20%5B%5D;%20%20for%20(var%20c%20=%200;%20c%20%3C%20brickColumnCount;%20c++)%20%7B%20%20%20%20%20bricks%5Bc%5D%20=%20%5B%5D;%20%20%20%20%20for%20(var%20r%20=%200;%20r%20%3C%20brickRowCount;%20r++)%20%7B%20%20%20%20%20%20%20%20%20bricks%5Bc%5D%5Br%5D%20=%20%7B%20x:%200,%20y:%200,%20status:%201%20%7D;%20%20%20%20%20%7D%20%7D%20%20var%20score%20=%200;%20var%20lives%20=%203;%20%20function%20drawBall()%20%7B%20%20%20%20%20ctx.beginPath();%20%20%20%20%20ctx.arc(x,%20y,%20ballRadius,%200,%20Math.PI%20*%202);%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fill();%20%20%20%20%20ctx.closePath();%20%7D%20%20function%20drawPaddle()%20%7B%20%20%20%20%20ctx.beginPath();%20%20%20%20%20ctx.rect(paddleX,%20canvas.height%20-%20paddleHeight,%20paddleWidth,%20paddleHeight);%20%20%20%20%20ctx.fillStyle%20=%20'grey';%20%20%20%20%20ctx.fill();%20%20%20%20%20ctx.closePath();%20%7D%20%20function%20drawBricks()%20%7B%20%20%20%20%20for%20(var%20c%20=%200;%20c%20%3C%20brickColumnCount;%20c++)%20%7B%20%20%20%20%20%20%20%20%20for%20(var%20r%20=%200;%20r%20%3C%20brickRowCount;%20r++)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(bricks%5Bc%5D%5Br%5D.status%20==%201)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20brickX%20=%20c%20*%20(brickWidth%20+%20brickPadding)%20+%20brickOffsetLeft;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20brickY%20=%20r%20*%20(brickHeight%20+%20brickPadding)%20+%20brickOffsetTop;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bricks%5Bc%5D%5Br%5D.x%20=%20brickX;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bricks%5Bc%5D%5Br%5D.y%20=%20brickY;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.beginPath();%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.rect(brickX,%20brickY,%20brickWidth,%20brickHeight);%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.fill();%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ctx.closePath();%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D%20%20function%20drawScore()%20%7B%20%20%20%20%20ctx.font%20=%20'16px%20Arial';%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fillText('Score:%20'%20+%20score,%208,%2020);%20%7D%20%20function%20drawLives()%20%7B%20%20%20%20%20ctx.font%20=%20'16px%20Arial';%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fillText('Lives:%20'%20+%20lives,%20canvas.width%20-%2065,%2020);%20%20%20%20%20ctx.font%20=%20'20px%20Arial';%20%20%20%20%20ctx.fillStyle%20=%20'black';%20%20%20%20%20ctx.fillText('Made%20by%20Emmanuel%20Ghattas',%20100,%2025);%20%7D%20%20function%20draw()%20%7B%20%20%20%20%20ctx.clearRect(0,%200,%20canvas.width,%20canvas.height);%20%20%20%20%20drawBricks();%20%20%20%20%20drawBall();%20%20%20%20%20drawPaddle();%20%20%20%20%20drawScore();%20%20%20%20%20drawLives();%20%20%20%20%20collisionDetection();%20%20%20%20%20%20if%20(x%20+%20dx%20%3E%20canvas.width%20-%20ballRadius%20%7C%7C%20x%20+%20dx%20%3C%20ballRadius)%20%7B%20%20%20%20%20%20%20%20%20dx%20=%20-dx;%20%20%20%20%20%7D%20%20%20%20%20if%20(y%20+%20dy%20%3C%20ballRadius)%20%7B%20%20%20%20%20%20%20%20%20dy%20=%20-dy;%20%20%20%20%20%7D%20else%20if%20(y%20+%20dy%20%3E%20canvas.height%20-%20ballRadius)%20%7B%20%20%20%20%20%20%20%20%20if%20(x%20%3E%20paddleX%20&&%20x%20%3C%20paddleX%20+%20paddleWidth)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%20-dy;%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20lives--;%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(!lives)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert('GAME%20OVER!%5CnGame%20by:%20Emmanuel%20Ghattas.%5CnBye-Bye!');%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20document.location.reload();%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%20=%20canvas.width%20/%202;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%20=%20canvas.height%20-%2030;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%200%20-%20dy;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%20(canvas.width%20-%20paddleWidth)%20/%202;%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%20%20%20%20%20x%20+=%20dx;%20%20%20%20%20y%20+=%20dy;%20%20%20%20%20requestAnimationFrame(draw);%20%7D%20%20function%20collisionDetection()%20%7B%20%20%20%20%20for%20(var%20c%20=%200;%20c%20%3C%20brickColumnCount;%20c++)%20%7B%20%20%20%20%20%20%20%20%20for%20(var%20r%20=%200;%20r%20%3C%20brickRowCount;%20r++)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20var%20b%20=%20bricks%5Bc%5D%5Br%5D;%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(b.status%20==%201)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(x%20%3E%20b.x%20&&%20x%20%3C%20b.x%20+%20brickWidth%20&&%20y%20%3E%20b.y%20&&%20y%20%3C%20b.y%20+%20brickHeight)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%20-dy;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20b.status%20=%200;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score++;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(score%20==%20brickRowCount%20*%20brickColumnCount)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alert('YOU%20WIN,%20CONGRATULATIONS!');%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20lives%20=%2099;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dx%20=%2010;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dy%20=%20-10;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20paddlespeed%20+=%202;%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D%20document.addEventListener('click',%20function(e)%20%7B%20%20%20%20%20var%20screenWidth%20=%20window.innerWidth;%20%20%20%20%20var%20clickX%20=%20e.clientX;%20%20%20%20%20if%20(clickX%20%3C%20screenWidth%20/%202)%20%7B%20%20%20%20%20%20%20%20%20paddleX%20-=%20paddlespeed;%20%20%20%20%20%20%20%20%20if%20(paddleX%20%3C%200)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%200;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20paddleX%20+=%20paddlespeed;%20%20%20%20%20%20%20%20%20if%20(paddleX%20+%20paddleWidth%20%3E%20canvas.width)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%20canvas.width%20-%20paddleWidth;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D);%20%20document.addEventListener('touchmove',%20function(e)%20%7B%20%20%20%20%20var%20screenWidth%20=%20window.innerWidth;%20%20%20%20%20var%20touchX%20=%20e.touches%5B0%5D.clientX;%20%20%20%20%20if%20(touchX%20%3C%20screenWidth%20/%202)%20%7B%20%20%20%20%20%20%20%20%20paddleX%20-=%204;%20%20%20%20%20%20%20%20%20if%20(paddleX%20%3C%200)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%200;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20else%20%7B%20%20%20%20%20%20%20%20%20paddleX%20+=%204;%20%20%20%20%20%20%20%20%20if%20(paddleX%20+%20paddleWidth%20%3E%20canvas.width)%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20paddleX%20=%20canvas.width%20-%20paddleWidth;%20%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%7D);%20%20draw();
Please, tell me if anything comes to mind.
1 Answer 1
I would consider creating an HTML version, stored as a Data URL for simpler storage and embedding.
I escaped the \n literal in the alert() call with \\n.
The bottom pad that blocks the moving object only moves left on desktop.
You'll have to edit the below code since SE is now prepending attribution, unless you copy the code directly a different way than what the UI offers...
data:text/html;base64,PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PHNjcmlwdD4vLyBTb3VyY2UgLSBodHRwczovL2NvZGVyZXZpZXcuc3RhY2tleGNoYW5nZS5jb20vcQovLyBQb3N0ZWQgYnkgQ2hpcDAxLCBtb2RpZmllZCBieSBjb21tdW5pdHkuIFNlZSBwb3N0ICdUaW1lbGluZScgZm9yIGNoYW5nZSBoaXN0b3J5Ci8vIFJldHJpZXZlZCAyMDI1LTEyLTA2LCBMaWNlbnNlIC0gQ0MgQlktU0EgNC4wCgovLyBDcmVhdGUgY2FudmFzCnZhciBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTsKZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjYW52YXMpOwoKY2FudmFzLnN0eWxlLnBvc2l0aW9uID0gImFic29sdXRlIjsKY2FudmFzLnN0eWxlLnRvcCA9ICI1MHB4IjsKY2FudmFzLnN0eWxlLmxlZnQgPSAiMHB4IjsKY2FudmFzLnN0eWxlLm9wYWNpdHkgPSAiMC41IjsKY2FudmFzLnN0eWxlLmJhY2tncm91bmRDb2xvciA9ICJ3aGl0ZSI7CmNhbnZhcy5zdHlsZS5ib3JkZXJDb2xvciA9ICJibGFjayI7CgpjYW52YXMud2lkdGggPSA0ODA7CmNhbnZhcy5oZWlnaHQgPSAzMjA7Cgp2YXIgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7CgovLyBDcmVhdGUgZXhpdCBidXR0b24KdmFyIGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpOwpkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGJ1dHRvbik7CgpidXR0b24uc3R5bGUucG9zaXRpb24gPSAiYWJzb2x1dGUiOwpidXR0b24uc3R5bGUudG9wID0gIjUwcHgiOwpidXR0b24uc3R5bGUubGVmdCA9ICI0ODBweCI7CmJ1dHRvbi5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiYmxhY2siOwpidXR0b24uc3R5bGUuYm9yZGVyQ29sb3IgPSAid2hpdGUiOwpidXR0b24uc3R5bGUud2lkdGggPSAiNTBweCI7CmJ1dHRvbi5zdHlsZS5oZWlnaHQgPSAiNTBweCI7CmJ1dHRvbi50ZXh0Q29udGVudCA9ICJFWElUIjsKYnV0dG9uLnN0eWxlLmNvbG9yID0gIndoaXRlIjsKYnV0dG9uLnN0eWxlLm9wYWNpdHkgPSAiMC41IjsKCmJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uICgpIHsKICAgIGRvY3VtZW50LmxvY2F0aW9uLnJlbG9hZCgpOwp9KTsKCi8vIEJhbGwgdmFyaWFibGVzCnZhciBiYWxsUmFkaXVzID0gNTsKdmFyIHggPSBjYW52YXMud2lkdGggLyAyOwp2YXIgeSA9IGNhbnZhcy5oZWlnaHQgLSAzMDsKdmFyIGR4ID0gMjsKdmFyIGR5ID0gLTI7CgovLyBQYWRkbGUgdmFyaWFibGVzCnZhciBwYWRkbGVIZWlnaHQgPSAxMDsKdmFyIHBhZGRsZVdpZHRoID0gNzU7CnZhciBwYWRkbGVYID0gKGNhbnZhcy53aWR0aCAtIHBhZGRsZVdpZHRoKSAvIDI7CnZhciBwYWRkbGVzcGVlZCA9IDc7CgovLyBCcmlja3MKdmFyIGJyaWNrUm93Q291bnQgPSA1Owp2YXIgYnJpY2tDb2x1bW5Db3VudCA9IDU7CnZhciBicmlja1dpZHRoID0gNzU7CnZhciBicmlja0hlaWdodCA9IDE1Owp2YXIgYnJpY2tQYWRkaW5nID0gMTA7CnZhciBicmlja09mZnNldFRvcCA9IDMwOwp2YXIgYnJpY2tPZmZzZXRMZWZ0ID0gMzA7Cgp2YXIgYnJpY2tzID0gW107Cgpmb3IgKHZhciBjID0gMDsgYyA8IGJyaWNrQ29sdW1uQ291bnQ7IGMrKykgewogICAgYnJpY2tzW2NdID0gW107CiAgICBmb3IgKHZhciByID0gMDsgciA8IGJyaWNrUm93Q291bnQ7IHIrKykgewogICAgICAgIGJyaWNrc1tjXVtyXSA9IHsgeDogMCwgeTogMCwgc3RhdHVzOiAxIH07CiAgICB9Cn0KCnZhciBzY29yZSA9IDA7CnZhciBsaXZlcyA9IDM7CgovLyBEcmF3IGJhbGwKZnVuY3Rpb24gZHJhd0JhbGwoKSB7CiAgICBjdHguYmVnaW5QYXRoKCk7CiAgICBjdHguYXJjKHgsIHksIGJhbGxSYWRpdXMsIDAsIE1hdGguUEkgKiAyKTsKICAgIGN0eC5maWxsU3R5bGUgPSAnYmxhY2snOwogICAgY3R4LmZpbGwoKTsKICAgIGN0eC5jbG9zZVBhdGgoKTsKfQoKLy8gRHJhdyBwYWRkbGUKZnVuY3Rpb24gZHJhd1BhZGRsZSgpIHsKICAgIGN0eC5iZWdpblBhdGgoKTsKICAgIGN0eC5yZWN0KHBhZGRsZVgsIGNhbnZhcy5oZWlnaHQgLSBwYWRkbGVIZWlnaHQsIHBhZGRsZVdpZHRoLCBwYWRkbGVIZWlnaHQpOwogICAgY3R4LmZpbGxTdHlsZSA9ICdncmV5JzsKICAgIGN0eC5maWxsKCk7CiAgICBjdHguY2xvc2VQYXRoKCk7Cn0KCi8vIERyYXcgYnJpY2tzCmZ1bmN0aW9uIGRyYXdCcmlja3MoKSB7CiAgICBmb3IgKHZhciBjID0gMDsgYyA8IGJyaWNrQ29sdW1uQ291bnQ7IGMrKykgewogICAgICAgIGZvciAodmFyIHIgPSAwOyByIDwgYnJpY2tSb3dDb3VudDsgcisrKSB7CiAgICAgICAgICAgIGlmIChicmlja3NbY11bcl0uc3RhdHVzID09IDEpIHsKICAgICAgICAgICAgICAgIHZhciBicmlja1ggPSBjICogKGJyaWNrV2lkdGggKyBicmlja1BhZGRpbmcpICsgYnJpY2tPZmZzZXRMZWZ0OwogICAgICAgICAgICAgICAgdmFyIGJyaWNrWSA9IHIgKiAoYnJpY2tIZWlnaHQgKyBicmlja1BhZGRpbmcpICsgYnJpY2tPZmZzZXRUb3A7CgogICAgICAgICAgICAgICAgYnJpY2tzW2NdW3JdLnggPSBicmlja1g7CiAgICAgICAgICAgICAgICBicmlja3NbY11bcl0ueSA9IGJyaWNrWTsKCiAgICAgICAgICAgICAgICBjdHguYmVnaW5QYXRoKCk7CiAgICAgICAgICAgICAgICBjdHgucmVjdChicmlja1gsIGJyaWNrWSwgYnJpY2tXaWR0aCwgYnJpY2tIZWlnaHQpOwogICAgICAgICAgICAgICAgY3R4LmZpbGxTdHlsZSA9ICdibGFjayc7CiAgICAgICAgICAgICAgICBjdHguZmlsbCgpOwogICAgICAgICAgICAgICAgY3R4LmNsb3NlUGF0aCgpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CgovLyBEcmF3IHNjb3JlCmZ1bmN0aW9uIGRyYXdTY29yZSgpIHsKICAgIGN0eC5mb250ID0gJzE2cHggQXJpYWwnOwogICAgY3R4LmZpbGxTdHlsZSA9ICdibGFjayc7CiAgICBjdHguZmlsbFRleHQoJ1Njb3JlOiAnICsgc2NvcmUsIDgsIDIwKTsKfQoKLy8gRHJhdyBsaXZlcwpmdW5jdGlvbiBkcmF3TGl2ZXMoKSB7CiAgICBjdHguZm9udCA9ICcxNnB4IEFyaWFsJzsKICAgIGN0eC5maWxsU3R5bGUgPSAnYmxhY2snOwogICAgY3R4LmZpbGxUZXh0KCdMaXZlczogJyArIGxpdmVzLCBjYW52YXMud2lkdGggLSA2NSwgMjApOwoKICAgIGN0eC5mb250ID0gJzIwcHggQXJpYWwnOwogICAgY3R4LmZpbGxUZXh0KCdNYWRlIGJ5IEVtbWFudWVsIEdoYXR0YXMnLCAxMDAsIDI1KTsKfQoKLy8gTWFpbiBkcmF3IGxvb3AKZnVuY3Rpb24gZHJhdygpIHsKICAgIGN0eC5jbGVhclJlY3QoMCwgMCwgY2FudmFzLndpZHRoLCBjYW52YXMuaGVpZ2h0KTsKCiAgICBkcmF3QnJpY2tzKCk7CiAgICBkcmF3QmFsbCgpOwogICAgZHJhd1BhZGRsZSgpOwogICAgZHJhd1Njb3JlKCk7CiAgICBkcmF3TGl2ZXMoKTsKICAgIGNvbGxpc2lvbkRldGVjdGlvbigpOwoKICAgIC8vIEJhbGwgY29sbGlzaW9uIHdpdGggd2FsbHMKICAgIGlmICh4ICsgZHggPiBjYW52YXMud2lkdGggLSBiYWxsUmFkaXVzIHx8IHggKyBkeCA8IGJhbGxSYWRpdXMpIHsKICAgICAgICBkeCA9IC1keDsKICAgIH0KCiAgICBpZiAoeSArIGR5IDwgYmFsbFJhZGl1cykgewogICAgICAgIGR5ID0gLWR5OwogICAgfSBlbHNlIGlmICh5ICsgZHkgPiBjYW52YXMuaGVpZ2h0IC0gYmFsbFJhZGl1cykgewogICAgICAgIGlmICh4ID4gcGFkZGxlWCAmJiB4IDwgcGFkZGxlWCArIHBhZGRsZVdpZHRoKSB7CiAgICAgICAgICAgIGR5ID0gLWR5OwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGxpdmVzLS07CiAgICAgICAgICAgIGlmICghbGl2ZXMpIHsKICAgICAgICAgICAgICAgIGFsZXJ0KCdHQU1FIE9WRVIhXG5HYW1lIGJ5OiBFbW1hbnVlbCBHaGF0dGFzLlxuQnllLUJ5ZSEnKTsKICAgICAgICAgICAgICAgIGRvY3VtZW50LmxvY2F0aW9uLnJlbG9hZCgpOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgeCA9IGNhbnZhcy53aWR0aCAvIDI7CiAgICAgICAgICAgICAgICB5ID0gY2FudmFzLmhlaWdodCAtIDMwOwogICAgICAgICAgICAgICAgZHkgPSAtZHk7CiAgICAgICAgICAgICAgICBwYWRkbGVYID0gKGNhbnZhcy53aWR0aCAtIHBhZGRsZVdpZHRoKSAvIDI7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgogICAgeCArPSBkeDsKICAgIHkgKz0gZHk7CgogICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGRyYXcpOwp9CgovLyBDb2xsaXNpb24gZGV0ZWN0aW9uCmZ1bmN0aW9uIGNvbGxpc2lvbkRldGVjdGlvbigpIHsKICAgIGZvciAodmFyIGMgPSAwOyBjIDwgYnJpY2tDb2x1bW5Db3VudDsgYysrKSB7CiAgICAgICAgZm9yICh2YXIgciA9IDA7IHIgPCBicmlja1Jvd0NvdW50OyByKyspIHsKICAgICAgICAgICAgdmFyIGIgPSBicmlja3NbY11bcl07CgogICAgICAgICAgICBpZiAoYi5zdGF0dXMgPT0gMSkgewogICAgICAgICAgICAgICAgaWYgKAogICAgICAgICAgICAgICAgICAgIHggPiBiLnggJiYKICAgICAgICAgICAgICAgICAgICB4IDwgYi54ICsgYnJpY2tXaWR0aCAmJgogICAgICAgICAgICAgICAgICAgIHkgPiBiLnkgJiYKICAgICAgICAgICAgICAgICAgICB5IDwgYi55ICsgYnJpY2tIZWlnaHQKICAgICAgICAgICAgICAgICkgewogICAgICAgICAgICAgICAgICAgIGR5ID0gLWR5OwogICAgICAgICAgICAgICAgICAgIGIuc3RhdHVzID0gMDtjb25zb2xlLmxvZwogICAgICAgICAgICAgICAgICAgIHNjb3JlKys7CgogICAgICAgICAgICAgICAgICAgIGlmIChzY29yZSA9PT0gYnJpY2tSb3dDb3VudCAqIGJyaWNrQ29sdW1uQ291bnQpIHsKICAgICAgICAgICAgICAgICAgICAgICAgYWxlcnQoJ1lPVSBXSU4sIENPTkdSQVRVTEFUSU9OUyEnKTsKICAgICAgICAgICAgICAgICAgICAgICAgbGl2ZXMgPSA5OTsKICAgICAgICAgICAgICAgICAgICAgICAgZHggPSAxMDsKICAgICAgICAgICAgICAgICAgICAgICAgZHkgPSAtMTA7CiAgICAgICAgICAgICAgICAgICAgICAgIHBhZGRsZXNwZWVkICs9IDI7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CgovLyBNb3VzZS90b3VjaCBjb250cm9scwpkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGZ1bmN0aW9uIChlKSB7CiAgICB2YXIgc2NyZWVuV2lkdGggPSB3aW5kb3cuaW5uZXJXaWR0aDsKICAgIHZhciBjbGlja1ggPSBlLmNsaWVudFg7CgogICAgaWYgKGNsaWNrWCA8IHNjcmVlbldpZHRoIC8gMikgewogICAgICAgIHBhZGRsZVggLT0gcGFkZGxlc3BlZWQ7CiAgICAgICAgaWYgKHBhZGRsZVggPCAwKSBwYWRkbGVYID0gMDsKICAgIH0gZWxzZSB7CiAgICAgICAgcGFkZGxlWCArPSBwYWRkbGVzcGVlZDsKICAgICAgICBpZiAocGFkZGxlWCArIHBhZGRsZVdpZHRoID4gY2FudmFzLndpZHRoKQogICAgICAgICAgICBwYWRkbGVYID0gY2FudmFzLndpZHRoIC0gcGFkZGxlV2lkdGg7CiAgICB9Cn0pOwoKZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgZnVuY3Rpb24gKGUpIHsKICAgIHZhciBzY3JlZW5XaWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoOwogICAgdmFyIHRvdWNoWCA9IGUudG91Y2hlc1swXS5jbGllbnRYOwoKICAgIGlmICh0b3VjaFggPCBzY3JlZW5XaWR0aCAvIDIpIHsKICAgICAgICBwYWRkbGVYIC09IHBhZGRsZXNwZWVkOwogICAgICAgIGlmIChwYWRkbGVYIDwgMCkgcGFkZGxlWCA9IDA7CiAgICB9IGVsc2UgewogICAgICAgIHBhZGRsZVggKz0gcGFkZGxlc3BlZWQ7CiAgICAgICAgaWYgKHBhZGRsZVggKyBwYWRkbGVXaWR0aCA+IGNhbnZhcy53aWR0aCkKICAgICAgICAgICAgcGFkZGxlWCA9IGNhbnZhcy53aWR0aCAtIHBhZGRsZVdpZHRoOwogICAgfQp9KTsKCi8vIFN0YXJ0IHRoZSBnYW1lCmRyYXcoKTsKPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPgo=
-
2\$\begingroup\$ Among other issues, I really don't think it's safe to copy and paste an opaque script. At the absolute least, I would need to see the original (non-packed) source. What's to stop you from embedding a virus in that data URL? \$\endgroup\$Reinderien– Reinderien2025年12月06日 15:22:36 +00:00Commented Dec 6 at 15:22
-
1\$\begingroup\$ @Reinderien What? The source is in OP. No idea what you mean by "embedding a virus in that data URL". Very simple, convert to plain text and read it before loading it in a browser tab, if you're scurred. Further, I don't know what kind of "virus" you think can be embedded in a data URL? \$\endgroup\$guest271314– guest2713142025年12月06日 16:01:47 +00:00Commented Dec 6 at 16:01
-
\$\begingroup\$ @Reinderien You mean you couldn't do this yourself?
var text = await (await fetch(dataURL)).text(); console.log(text);? \$\endgroup\$guest271314– guest2713142025年12月06日 16:14:58 +00:00Commented Dec 6 at 16:14
touchmove. \$\endgroup\$constin place of most of thosevar? Is there a browser you're targeting that doesn't support it? \$\endgroup\$