Skip to content

Commit 9e76e28

Browse files
committed
standalone script
1 parent ac4b964 commit 9e76e28

File tree

2 files changed

+170
-171
lines changed

2 files changed

+170
-171
lines changed

app/index.html

Lines changed: 1 addition & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -57,175 +57,5 @@
5757

5858
</body>
5959

60-
<script type="module">
61-
if (!window.WebAssembly) {
62-
alert("WebAssembly is not supported in your browser. Please use a modern browser.");
63-
}
64-
65-
const secretInput = document.getElementById('secretInput');
66-
const fileInput = document.getElementById('fileInput');
67-
const limitMaxSideInput = document.getElementById('limitMaxSide');
68-
const maxSideInput = document.getElementById('maxSide');
69-
const inputImgDiv = document.getElementById('inputImg');
70-
const outputDiv = document.getElementById('output');
71-
const hintLabel = document.getElementById('hint');
72-
const encodeButton = document.getElementById('encodeButton');
73-
const decodeButton = document.getElementById('decodeButton');
74-
const downloadBtnContainer = document.getElementById('downloadBtnContainer');
75-
const downloadBtn = document.getElementById('downloadBtn');
76-
const errorDiv = document.getElementById('error');
77-
const worker = new Worker('./worker.js', { type: 'module' });
78-
79-
const urlParams = new URLSearchParams(window.location.search);
80-
const secretFromUrl = urlParams.get('secret') || urlParams.get('s');
81-
if (secretFromUrl) {
82-
secretInput.value = decodeURIComponent(secretFromUrl);
83-
}
84-
85-
async function getInputBlob() {
86-
const file = fileInput.files[0];
87-
const arrayBuffer = await file.arrayBuffer();
88-
return new Uint8Array(arrayBuffer);
89-
}
90-
91-
function checkInput() {
92-
if (fileInput.files.length === 0) {
93-
showError("No image file selected");
94-
throw new Error("No image file selected");
95-
}
96-
if (secretInput.value.trim() === '') {
97-
showError("Secret cannot be empty");
98-
throw new Error("Secret cannot be empty");
99-
}
100-
}
101-
102-
async function showError(msg) {
103-
errorDiv.textContent = msg;
104-
errorDiv.style.display = 'block';
105-
console.error(msg);
106-
}
107-
108-
function resetOutput() {
109-
inputImgDiv.innerHTML = '';
110-
outputDiv.innerHTML = '';
111-
errorDiv.textContent = '';
112-
errorDiv.style.display = 'none';
113-
downloadBtnContainer.style.display = 'none';
114-
hintLabel.textContent = 'Enter a secret and select an image file to encode / decode';
115-
}
116-
117-
async function showImage(imBlob) {
118-
resetOutput();
119-
hintLabel.textContent = '';
120-
const blob = new Blob([imBlob], { type: 'image/png' });
121-
const url = URL.createObjectURL(blob);
122-
123-
const imgElem = document.createElement('img');
124-
imgElem.src = url;
125-
imgElem.alt = 'Image';
126-
outputDiv.appendChild(imgElem);
127-
128-
downloadBtnContainer.style.display = 'block';
129-
downloadBtn.onclick = () => {
130-
const a = document.createElement('a');
131-
a.href = url;
132-
const timeName = new Date().toISOString().replace(/[:.]/g, '-');
133-
a.download = `img-${timeName}.png`;
134-
document.body.appendChild(a);
135-
a.click();
136-
document.body.removeChild(a);
137-
};
138-
}
139-
140-
async function encode_image() {
141-
checkInput();
142-
resetOutput();
143-
const inputBlob = await getInputBlob();
144-
hintLabel.textContent = `Encoding...`;
145-
worker.postMessage({
146-
type: 'encode',
147-
buffer: inputBlob,
148-
secret: secretInput.value,
149-
maxSide: limitMaxSideInput.checked ? parseInt(maxSideInput.value) : -1
150-
});
151-
}
152-
153-
async function decode_image() {
154-
checkInput();
155-
resetOutput();
156-
const inputBlob = await getInputBlob();
157-
hintLabel.textContent = `Decoding...`;
158-
worker.postMessage({
159-
type: 'decode',
160-
buffer: inputBlob,
161-
secret: secretInput.value,
162-
maxSide: limitMaxSideInput.checked ? parseInt(maxSideInput.value) : -1
163-
});
164-
}
165-
166-
worker.onmessage = async (event) => {
167-
if (event.data.error) {
168-
await showError(`Error decoding: ${event.data.error}`);
169-
console.error(event.data.error);
170-
return;
171-
}
172-
await showImage(event.data.buffer);
173-
};
174-
175-
encodeButton.addEventListener('click', encode_image);
176-
decodeButton.addEventListener('click', decode_image);
177-
fileInput.addEventListener('change', ()=>{
178-
resetOutput();
179-
hintLabel.textContent += ' (Below is the selected image)';
180-
const file = fileInput.files[0];
181-
if (file) {
182-
const imgElem = document.createElement('img');
183-
imgElem.src = URL.createObjectURL(file);
184-
imgElem.alt = 'Selected Image';
185-
inputImgDiv.innerHTML = '';
186-
inputImgDiv.appendChild(imgElem);
187-
}
188-
});
189-
190-
// handle drag and drop
191-
{
192-
const dropZone = document.getElementById('drop-zone');
193-
let inDrag = false;
194-
let taskId = null;
195-
function hideDropZone() {
196-
if (inDrag) return;
197-
dropZone.style.display = 'none';
198-
}
199-
window.addEventListener('dragover', (event) => {
200-
event.preventDefault();
201-
dropZone.style.display = 'block';
202-
inDrag = true;
203-
if (taskId) { window.clearTimeout(taskId); }
204-
taskId = window.setTimeout(hideDropZone, 100);
205-
});
206-
window.addEventListener('dragmove', (event) => {
207-
event.preventDefault();
208-
dropZone.style.display = 'block';
209-
inDrag = true;
210-
if (taskId) { window.clearTimeout(taskId); }
211-
taskId = window.setTimeout(hideDropZone, 100);
212-
});
213-
window.addEventListener('dragleave', (event) => {
214-
event.preventDefault();
215-
inDrag = false;
216-
if (taskId) { window.clearTimeout(taskId); }
217-
taskId = window.setTimeout(hideDropZone, 100);
218-
});
219-
dropZone.addEventListener('drop', (event) => {
220-
event.preventDefault();
221-
if (event.dataTransfer.files.length > 0) {
222-
fileInput.files = event.dataTransfer.files;
223-
fileInput.dispatchEvent(new Event('change'));
224-
}
225-
inDrag = false;
226-
dropZone.style.display = 'none';
227-
});
228-
}
229-
230-
</script>
60+
<script src="./script.js" type="module"></script>
23161
</html>

app/script.js

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
2+
if (!window.WebAssembly) {
3+
alert("WebAssembly is not supported in your browser. Please use a modern browser.");
4+
}
5+
6+
const secretInput = document.getElementById('secretInput');
7+
const fileInput = document.getElementById('fileInput');
8+
const limitMaxSideInput = document.getElementById('limitMaxSide');
9+
const maxSideInput = document.getElementById('maxSide');
10+
const inputImgDiv = document.getElementById('inputImg');
11+
const outputDiv = document.getElementById('output');
12+
const hintLabel = document.getElementById('hint');
13+
const encodeButton = document.getElementById('encodeButton');
14+
const decodeButton = document.getElementById('decodeButton');
15+
const downloadBtnContainer = document.getElementById('downloadBtnContainer');
16+
const downloadBtn = document.getElementById('downloadBtn');
17+
const errorDiv = document.getElementById('error');
18+
const worker = new Worker('./worker.js', { type: 'module' });
19+
20+
const urlParams = new URLSearchParams(window.location.search);
21+
const secretFromUrl = urlParams.get('secret') || urlParams.get('s');
22+
if (secretFromUrl) {
23+
secretInput.value = decodeURIComponent(secretFromUrl);
24+
}
25+
26+
async function getInputBlob() {
27+
const file = fileInput.files[0];
28+
const arrayBuffer = await file.arrayBuffer();
29+
return new Uint8Array(arrayBuffer);
30+
}
31+
32+
function checkInput() {
33+
if (fileInput.files.length === 0) {
34+
showError("No image file selected");
35+
throw new Error("No image file selected");
36+
}
37+
if (secretInput.value.trim() === '') {
38+
showError("Secret cannot be empty");
39+
throw new Error("Secret cannot be empty");
40+
}
41+
}
42+
43+
async function showError(msg) {
44+
errorDiv.textContent = msg;
45+
errorDiv.style.display = 'block';
46+
console.error(msg);
47+
}
48+
49+
function resetOutput() {
50+
inputImgDiv.innerHTML = '';
51+
outputDiv.innerHTML = '';
52+
errorDiv.textContent = '';
53+
errorDiv.style.display = 'none';
54+
downloadBtnContainer.style.display = 'none';
55+
hintLabel.textContent = 'Enter a secret and select an image file to encode / decode';
56+
}
57+
58+
async function showImage(imBlob) {
59+
resetOutput();
60+
hintLabel.textContent = '';
61+
const blob = new Blob([imBlob], { type: 'image/png' });
62+
const url = URL.createObjectURL(blob);
63+
64+
const imgElem = document.createElement('img');
65+
imgElem.src = url;
66+
imgElem.alt = 'Image';
67+
outputDiv.appendChild(imgElem);
68+
69+
downloadBtnContainer.style.display = 'block';
70+
downloadBtn.onclick = () => {
71+
const a = document.createElement('a');
72+
a.href = url;
73+
const timeName = new Date().toISOString().replace(/[:.]/g, '-');
74+
a.download = `img-${timeName}.png`;
75+
document.body.appendChild(a);
76+
a.click();
77+
document.body.removeChild(a);
78+
};
79+
}
80+
81+
async function encode_image() {
82+
checkInput();
83+
resetOutput();
84+
const inputBlob = await getInputBlob();
85+
hintLabel.textContent = `Encoding...`;
86+
worker.postMessage({
87+
type: 'encode',
88+
buffer: inputBlob,
89+
secret: secretInput.value,
90+
maxSide: limitMaxSideInput.checked ? parseInt(maxSideInput.value) : -1
91+
});
92+
}
93+
94+
async function decode_image() {
95+
checkInput();
96+
resetOutput();
97+
const inputBlob = await getInputBlob();
98+
hintLabel.textContent = `Decoding...`;
99+
worker.postMessage({
100+
type: 'decode',
101+
buffer: inputBlob,
102+
secret: secretInput.value,
103+
maxSide: limitMaxSideInput.checked ? parseInt(maxSideInput.value) : -1
104+
});
105+
}
106+
107+
worker.onmessage = async (event) => {
108+
if (event.data.error) {
109+
await showError(`Error decoding: ${event.data.error}`);
110+
console.error(event.data.error);
111+
return;
112+
}
113+
await showImage(event.data.buffer);
114+
};
115+
116+
encodeButton.addEventListener('click', encode_image);
117+
decodeButton.addEventListener('click', decode_image);
118+
fileInput.addEventListener('change', ()=>{
119+
resetOutput();
120+
hintLabel.textContent += ' (Below is the selected image)';
121+
const file = fileInput.files[0];
122+
if (file) {
123+
const imgElem = document.createElement('img');
124+
imgElem.src = URL.createObjectURL(file);
125+
imgElem.alt = 'Selected Image';
126+
inputImgDiv.innerHTML = '';
127+
inputImgDiv.appendChild(imgElem);
128+
}
129+
});
130+
131+
// handle drag and drop
132+
{
133+
const dropZone = document.getElementById('drop-zone');
134+
let inDrag = false;
135+
let taskId = null;
136+
function hideDropZone() {
137+
if (inDrag) return;
138+
dropZone.style.display = 'none';
139+
}
140+
window.addEventListener('dragover', (event) => {
141+
event.preventDefault();
142+
dropZone.style.display = 'block';
143+
inDrag = true;
144+
if (taskId) { window.clearTimeout(taskId); }
145+
taskId = window.setTimeout(hideDropZone, 100);
146+
});
147+
window.addEventListener('dragmove', (event) => {
148+
event.preventDefault();
149+
dropZone.style.display = 'block';
150+
inDrag = true;
151+
if (taskId) { window.clearTimeout(taskId); }
152+
taskId = window.setTimeout(hideDropZone, 100);
153+
});
154+
window.addEventListener('dragleave', (event) => {
155+
event.preventDefault();
156+
inDrag = false;
157+
if (taskId) { window.clearTimeout(taskId); }
158+
taskId = window.setTimeout(hideDropZone, 100);
159+
});
160+
dropZone.addEventListener('drop', (event) => {
161+
event.preventDefault();
162+
if (event.dataTransfer.files.length > 0) {
163+
fileInput.files = event.dataTransfer.files;
164+
fileInput.dispatchEvent(new Event('change'));
165+
}
166+
inDrag = false;
167+
dropZone.style.display = 'none';
168+
});
169+
}

0 commit comments

Comments
 (0)