diff --git a/src/Application/exportService.js b/src/Application/exportService.js
index bb724dd..90a3f49 100644
--- a/src/Application/exportService.js
+++ b/src/Application/exportService.js
@@ -24,10 +24,16 @@
`${fd.orderNr.replace('/', '-')}_inspectie_${new Date().toISOString().slice(0, 10)}.xml`);
let pc = 0;
for (const [nr, photos] of Object.entries(fd.photos)) {
- photos.forEach((p, i) => { pc++; I.downloadBlob(I.dataUrlToBlob(p.dataUrl), `${fd.orderNr.replace('/', '-')}_loc${nr}_foto${i + 1}.jpg`); });
+ photos.forEach((p, i) => {
+ pc++;
+ I.downloadBlob(p.blob, `${fd.orderNr.replace('/', '-')}_loc${nr}_foto${i + 1}.jpg`);
+ });
}
for (const [pos, photos] of Object.entries(fd.overviewPhotos)) {
- photos.forEach((p, i) => { pc++; I.downloadBlob(I.dataUrlToBlob(p.dataUrl), `${fd.orderNr.replace('/', '-')}_${pos}_foto${i + 1}.jpg`); });
+ photos.forEach((p, i) => {
+ pc++;
+ I.downloadBlob(p.blob, `${fd.orderNr.replace('/', '-')}_${pos}_foto${i + 1}.jpg`);
+ });
}
alert(`Opgeslagen!\n- 1 XML-bestand\n- ${pc} foto('s)`);
};
diff --git a/src/Application/photoService.js b/src/Application/photoService.js
index d660afa..1af0c60 100644
--- a/src/Application/photoService.js
+++ b/src/Application/photoService.js
@@ -1,4 +1,8 @@
(function (A, D, I) {
+ function photoSrc(p) {
+ return URL.createObjectURL(p.blob);
+ }
+
A.openPhotoModal = function (nr, loc) {
A.state.currentPhotoRow = nr;
document.getElementById('photoModalTitle').textContent = `Foto's - Nr ${nr}: ${loc}`;
@@ -17,7 +21,7 @@
for (const file of e.target.files) {
if (!A.state.formData.photos[row]) A.state.formData.photos[row] = [];
A.state.formData.photos[row].push({
- dataUrl: await I.readFileAsDataUrl(file),
+ blob: file,
timestamp: new Date().toISOString(),
gps: await I.getGPS(),
filename: file.name
@@ -39,14 +43,19 @@
}
grid.innerHTML = photos.map((p, i) => `
-

+
${new Date(p.timestamp).toLocaleTimeString('nl-NL', { hour: '2-digit', minute: '2-digit' })}${p.gps ? ' \u2316' : ''}
`).join('');
+ photos.forEach((p, i) => {
+ const img = grid.querySelector(`img[data-r="${row}"][data-i="${i}"]`);
+ if (img) img.src = photoSrc(p);
+ });
+
grid.querySelectorAll('img[data-r]').forEach(img => img.addEventListener('click', () => {
const ph = A.state.formData.photos[img.dataset.r]?.[+img.dataset.i];
- if (ph) A.openLightbox(ph.dataUrl);
+ if (ph) A.openLightbox(photoSrc(ph));
}));
grid.querySelectorAll('button[data-action="delete-photo"]').forEach(btn => btn.addEventListener('click', (ev) => {
ev.stopPropagation();
@@ -84,7 +93,7 @@
if (!A.state.formData.overviewPhotos[pos]) A.state.formData.overviewPhotos[pos] = [];
for (const file of e.target.files) {
A.state.formData.overviewPhotos[pos].push({
- dataUrl: await I.readFileAsDataUrl(file),
+ blob: file,
timestamp: new Date().toISOString(),
gps: await I.getGPS(),
filename: file.name
@@ -121,15 +130,20 @@
}
grid.innerHTML = all.map(it => `
-

+
${it.label}
`).join('');
+ all.forEach(it => {
+ const img = grid.querySelector(`img[data-pos="${it.pos}"][data-idx="${it.index}"]`);
+ if (img) img.src = photoSrc(it.photo);
+ });
+
grid.querySelectorAll('img[data-pos]').forEach(img => img.addEventListener('click', ev => {
ev.stopPropagation();
const ph = A.state.formData.overviewPhotos[img.dataset.pos]?.[+img.dataset.idx];
- if (ph) A.openLightbox(ph.dataUrl);
+ if (ph) A.openLightbox(photoSrc(ph));
}));
grid.querySelectorAll('button[data-action="delete-ov-photo"]').forEach(btn => btn.addEventListener('click', ev => {
ev.stopPropagation();
@@ -152,12 +166,18 @@
};
A.openLightbox = function (src) {
- document.getElementById('lightboxImg').src = src;
+ const img = document.getElementById('lightboxImg');
+ const prev = img.src;
+ img.src = src;
document.getElementById('lightbox').classList.add('active');
+ if (prev && prev.startsWith('blob:')) URL.revokeObjectURL(prev);
};
A.closeLightbox = function () {
+ const img = document.getElementById('lightboxImg');
+ const src = img.src;
document.getElementById('lightbox').classList.remove('active');
- document.getElementById('lightboxImg').src = '';
+ img.src = '';
+ if (src && src.startsWith('blob:')) URL.revokeObjectURL(src);
};
})(window.App.Application, window.App.Domain, window.App.Infrastructure);
diff --git a/src/Infrastructure/db.js b/src/Infrastructure/db.js
index ab859f2..6408a23 100644
--- a/src/Infrastructure/db.js
+++ b/src/Infrastructure/db.js
@@ -27,7 +27,7 @@
const d = await ensureDb();
return new Promise((resolve, reject) => {
const tx = d.transaction('inspections', 'readwrite');
- tx.objectStore('inspections').put(JSON.parse(JSON.stringify(formData)));
+ tx.objectStore('inspections').put(formData);
tx.oncomplete = () => resolve();
tx.onerror = reject;
});
diff --git a/src/Infrastructure/utils.js b/src/Infrastructure/utils.js
index 74b83b1..c9d5ea6 100644
--- a/src/Infrastructure/utils.js
+++ b/src/Infrastructure/utils.js
@@ -11,23 +11,6 @@
URL.revokeObjectURL(a.href);
};
- I.dataUrlToBlob = function (dataUrl) {
- const parts = dataUrl.split(',');
- const mime = parts[0].match(/:(.*?);/)[1];
- const bin = atob(parts[1]);
- const arr = new Uint8Array(bin.length);
- for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
- return new Blob([arr], { type: mime });
- };
-
- I.readFileAsDataUrl = function (file) {
- return new Promise(resolve => {
- const fr = new FileReader();
- fr.onload = () => resolve(fr.result);
- fr.readAsDataURL(file);
- });
- };
-
I.formatDate = function (d) {
if (!d || d.length !== 8) return d || '-';
return d.substring(6, 8) + '.' + d.substring(4, 6) + '.' + d.substring(0, 4);