Skip to content

Commit c3ca2e2

Browse files
author
Saurabh Kumar Bajpai
committed
fix: code quality and safety improvements
1 parent af173a5 commit c3ca2e2

5 files changed

Lines changed: 426 additions & 568 deletions

File tree

‎frontend/js/ambient.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,19 +489,19 @@ document.addEventListener('DOMContentLoaded', () => {
489489

490490
const type = Math.random();
491491
if (type < 0.5) {
492-
el.innerHTML = `<svg width="${size}" height="${size}" viewBox="0 0 20 20">
492+
el.textContent = `<svg width="${size}" height="${size}" viewBox="0 0 20 20">
493493
<path d="M10 1 L11.5 8.5 L19 10 L11.5 11.5 L10 19 L8.5 11.5 L1 10 L8.5 8.5 Z"
494494
fill="${color}" opacity="0.9"/></svg>`;
495495
} else if (type < 0.75) {
496496
const s = size * 0.7;
497-
el.innerHTML = `<svg width="${s}" height="${s}" viewBox="0 0 14 14">
497+
el.textContent = `<svg width="${s}" height="${s}" viewBox="0 0 14 14">
498498
<circle cx="7" cy="7" r="5" fill="${color}" opacity="0.85"/>
499499
<line x1="7" y1="0" x2="7" y2="14" stroke="${color}" stroke-width="1.5" opacity="0.5"/>
500500
<line x1="0" y1="7" x2="14" y2="7" stroke="${color}" stroke-width="1.5" opacity="0.5"/>
501501
</svg>`;
502502
} else {
503503
const s = size * 0.8;
504-
el.innerHTML = `<svg width="${s}" height="${s}" viewBox="0 0 20 20">
504+
el.textContent = `<svg width="${s}" height="${s}" viewBox="0 0 20 20">
505505
<polygon points="10,2 12,8 18,8 13,12 15,18 10,14 5,18 7,12 2,8 8,8"
506506
fill="${color}" opacity="0.9"/></svg>`;
507507
}

‎frontend/js/app.js‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ const CollectionAPI = {
152152
method: 'POST',
153153
headers: this.getHeaders(),
154154
credentials: 'include',
155-
body: JSON.stringify({ user_id: parseInt(userId), name, description, is_public: isPublic })
155+
body: JSON.stringify({ user_id: parseInt(userId, 10), name, description, is_public: isPublic })
156156
});
157157
if (!res.ok) {
158158
const errData = await res.json().catch(() => ({}));
@@ -222,7 +222,7 @@ const CollectionAPI = {
222222
headers: this.getHeaders(),
223223
credentials: 'include',
224224
body: JSON.stringify({
225-
user_id: parseInt(userId),
225+
user_id: parseInt(userId, 10),
226226
google_books_id: bookId,
227227
title: title,
228228
authors: Array.isArray(authors) ? authors.join(', ') : authors,
@@ -939,7 +939,7 @@ class BookRenderer {
939939
const slider = scene.querySelector('.progress-slider');
940940
if (slider) {
941941
slider.addEventListener('change', (e) => {
942-
const newProgress = parseInt(e.target.value);
942+
const newProgress = parseInt(e.target.value, 10);
943943
if (this.libraryManager) {
944944
this.libraryManager.updateBook(id, { progress: newProgress });
945945
}
@@ -3483,7 +3483,7 @@ document.addEventListener('DOMContentLoaded', async () => {
34833483

34843484
if (saveGoalBtn) {
34853485
saveGoalBtn.addEventListener('click', async () => {
3486-
const target = parseInt(goalInput.value);
3486+
const target = parseInt(goalInput.value, 10);
34873487
if (isNaN(target) || target < 1) return;
34883488

34893489
const token = SafeStorage.get('bibliodrift_token');
@@ -3782,13 +3782,13 @@ document.addEventListener('DOMContentLoaded', async () => {
37823782
const saveBtn = card.querySelector('.progress-card-save-btn');
37833783

37843784
slider.addEventListener('input', () => {
3785-
const val = parseInt(slider.value);
3785+
const val = parseInt(slider.value, 10);
37863786
barFill.style.width = `${val}%`;
37873787
pctLabel.textContent = `${val}%`;
37883788
});
37893789

37903790
saveBtn.addEventListener('click', async () => {
3791-
const newProgress = parseInt(slider.value);
3791+
const newProgress = parseInt(slider.value, 10);
37923792
saveBtn.disabled = true;
37933793
saveBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i>';
37943794
try {

‎frontend/js/book-preview.js‎

Lines changed: 1 addition & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -209,146 +209,4 @@ const BookPreview = (() => {
209209
el.querySelector('#download-card-btn').addEventListener('click', () => {
210210
const card = document.getElementById('book-card');
211211
html2canvas(card).then(canvas => {
212-
const link = document.createElement('a');
213-
link.download = 'book-card.png';
214-
link.href = canvas.toDataURL('image/png');
215-
link.click();
216-
});
217-
});
218-
219-
return el;
220-
}
221-
222-
// ── State helpers ──────────────────────────────────────────────────────────
223-
224-
function _setLoading() {
225-
const loading = document.getElementById('preview-loading');
226-
const container = document.getElementById('preview-viewer-container');
227-
const fallback = document.getElementById('preview-fallback');
228-
if (loading) loading.style.display = 'flex';
229-
if (container) { container.style.display = 'none'; container.innerHTML = ''; }
230-
if (fallback) fallback.style.display = 'none';
231-
}
232-
233-
function _showViewer() {
234-
const loading = document.getElementById('preview-loading');
235-
const container = document.getElementById('preview-viewer-container');
236-
const fallback = document.getElementById('preview-fallback');
237-
if (loading) loading.style.display = 'none';
238-
if (fallback) fallback.style.display = 'none';
239-
if (container) container.style.display = 'block';
240-
}
241-
242-
function _showFallback(id, msg) {
243-
const loading = document.getElementById('preview-loading');
244-
const container = document.getElementById('preview-viewer-container');
245-
const fallback = document.getElementById('preview-fallback');
246-
const msgEl = document.getElementById('preview-fallback-msg');
247-
const link = document.getElementById('preview-external-link');
248-
if (loading) loading.style.display = 'none';
249-
if (container) container.style.display = 'none';
250-
if (msgEl && msg) msgEl.textContent = msg;
251-
if (link) link.href = `https://books.google.com/books?id=${encodeURIComponent(id)}`;
252-
if (fallback) fallback.style.display = 'flex';
253-
}
254-
255-
function _close() {
256-
const modal = document.getElementById('book-preview-modal');
257-
const container = document.getElementById('preview-viewer-container');
258-
if (container) container.innerHTML = ''; // destroy iframe
259-
if (modal && modal.hasAttribute('open')) modal.close();
260-
document.body.style.overflow = '';
261-
}
262-
263-
// ── Viewer ─────────────────────────────────────────────────────────────────
264-
265-
function _renderViewer(id) {
266-
const container = document.getElementById('preview-viewer-container');
267-
if (!container) { _showFallback(id, 'Viewer container missing.'); return; }
268-
269-
if (!window.google?.books?.DefaultViewer) {
270-
_showFallback(id, 'The preview viewer could not be initialised.');
271-
return;
272-
}
273-
274-
// Hard timeout — show fallback if callbacks never fire
275-
const timeout = setTimeout(() => {
276-
_showFallback(id, 'The preview took too long to load. You can view it on Google Books instead.');
277-
}, 10000);
278-
279-
const viewer = new window.google.books.DefaultViewer(container);
280-
281-
viewer.load(
282-
id,
283-
// notFoundCallback — no embeddable preview for this book
284-
() => {
285-
clearTimeout(timeout);
286-
_showFallback(id, "This book doesn't have an embeddable preview. You can view it on Google Books instead.");
287-
},
288-
// successCallback — viewer rendered successfully
289-
() => {
290-
clearTimeout(timeout);
291-
_showViewer();
292-
}
293-
);
294-
}
295-
296-
// ── Public API ─────────────────────────────────────────────────────────────
297-
298-
/**
299-
* Open the in-app preview modal.
300-
* @param {string} googleBooksId
301-
* @param {string} [title]
302-
* @param {string} [author]
303-
* @param {number} [rating]
304-
* @param {string} [genre]
305-
*/
306-
307-
async function open(googleBooksId, title, author, rating, genre) {
308-
if (!_isValidId(googleBooksId)) {
309-
console.warn('[BookPreview] Invalid Google Books ID:', googleBooksId);
310-
return;
311-
}
312-
313-
const modal = _getOrCreateModal();
314-
315-
// Set title
316-
const titleEl = document.getElementById('preview-modal-title');
317-
if (titleEl) titleEl.textContent = title || 'Book Preview';
318-
319-
// populate the book card with real data after modal exists ──
320-
populateBookCard(title, author, rating, genre);
321-
322-
_setLoading();
323-
modal.showModal();
324-
document.body.style.overflow = 'hidden';
325-
326-
try {
327-
await _loadAPI();
328-
_renderViewer(googleBooksId);
329-
} catch (err) {
330-
console.error('[BookPreview] Error:', err);
331-
_showFallback(
332-
googleBooksId,
333-
'Something went wrong loading the preview. You can view this book on Google Books instead.'
334-
);
335-
}
336-
}
337-
338-
// populate hidden book card with current book's data
339-
function populateBookCard(title, author, rating, genre) {
340-
const titleEl = document.getElementById('card-title');
341-
const authorEl = document.getElementById('card-author');
342-
const ratingEl = document.getElementById('card-rating');
343-
const genreEl = document.getElementById('card-genre');
344-
if (titleEl) titleEl.textContent = title || '';
345-
if (authorEl) authorEl.textContent = author ? 'by ' + author : '';
346-
if (ratingEl) ratingEl.textContent = rating ? '★'.repeat(rating) + '☆'.repeat(5 - rating) : '';
347-
if (genreEl) genreEl.textContent = genre || '';
348-
}
349-
350-
return { open, populateBookCard };
351-
352-
})();
353-
354-
window.BookPreview = BookPreview;
212+
.catch(err => console.error(err))

‎frontend/js/library-3d.js‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,7 +2407,7 @@ class BookshelfRenderer3D {
24072407
if (progressBadge) progressBadge.textContent = `${clamped}% `;
24082408
// Sync pages input
24092409
if (pagesReadInput && pagesTotalInput) {
2410-
const pages = Math.round((clamped / 100) * parseInt(pagesTotalInput.value || totalPages));
2410+
const pages = Math.round((clamped / 100) * parseInt(pagesTotalInput.value || totalPages, 10));
24112411
pagesReadInput.value = pages;
24122412
}
24132413
if (pagesBar) pagesBar.style.width = `${clamped}% `;
@@ -2450,12 +2450,12 @@ class BookshelfRenderer3D {
24502450
progressSlider.parentNode.replaceChild(newSlider, progressSlider);
24512451
newSlider.value = currentProgress;
24522452
newSlider.addEventListener('input', () => {
2453-
const pct = parseInt(newSlider.value);
2453+
const pct = parseInt(newSlider.value, 10);
24542454
if (progressBar) progressBar.style.width = `${pct}% `;
24552455
if (progressValue) progressValue.textContent = `${pct}% `;
24562456
if (progressBadge) progressBadge.textContent = `${pct}% `;
24572457
// Sync pages
2458-
const total = parseInt(document.getElementById('modal-pages-total')?.value || totalPages);
2458+
const total = parseInt(document.getElementById('modal-pages-total', 10)?.value || totalPages);
24592459
const pages = Math.round((pct / 100) * total);
24602460
const pagesReadEl = document.getElementById('modal-pages-read');
24612461
if (pagesReadEl) pagesReadEl.value = pages;
@@ -2469,8 +2469,8 @@ class BookshelfRenderer3D {
24692469
const pagesTotalEl = document.getElementById('modal-pages-total');
24702470
const sliderEl = document.getElementById('modal-progress-slider');
24712471
if (!pagesReadEl || !pagesTotalEl) return;
2472-
const read = Math.max(0, parseInt(pagesReadEl.value) || 0);
2473-
const total = Math.max(1, parseInt(pagesTotalEl.value) || 1);
2472+
const read = Math.max(0, parseInt(pagesReadEl.value, 10) || 0);
2473+
const total = Math.max(1, parseInt(pagesTotalEl.value, 10) || 1);
24742474
const pct = Math.min(100, Math.round((read / total) * 100));
24752475
if (sliderEl) sliderEl.value = pct;
24762476
if (progressBar) progressBar.style.width = `${pct}% `;
@@ -2497,7 +2497,7 @@ class BookshelfRenderer3D {
24972497
progressSaveBtn.parentNode.replaceChild(newSaveBtn, progressSaveBtn);
24982498
newSaveBtn.addEventListener('click', async () => {
24992499
const sliderEl = document.getElementById('modal-progress-slider');
2500-
const newProgress = sliderEl ? parseInt(sliderEl.value) : currentProgress;
2500+
const newProgress = sliderEl ? parseInt(sliderEl.value, 10) : currentProgress;
25012501

25022502
newSaveBtn.disabled = true;
25032503
newSaveBtn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Saving...';

0 commit comments

Comments
 (0)