+ `;
- // Build the gallery container HTML including the slider.
- let galleryHTML = sliderHTML;
- galleryHTML += `
`;
- filteredFiles.forEach((file) => {
+ // slice current page
+ const startIdx = (currentPage - 1) * itemsPerPage;
+ const pageFiles = filteredFiles.slice(startIdx, startIdx + itemsPerPage);
+
+ pageFiles.forEach((file, idx) => {
+ const idSafe = encodeURIComponent(file.name) + "-" + (startIdx + idx);
+
+ // thumbnail
let thumbnail;
- if (/\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i.test(file.name)) {
+ if (/\.(jpe?g|png|gif|bmp|webp|svg|ico)$/i.test(file.name)) {
const cacheKey = folderPath + encodeURIComponent(file.name);
if (window.imageCache && window.imageCache[cacheKey]) {
- thumbnail = `

`;
+ thumbnail = `

`;
} else {
- const imageUrl = folderPath + encodeURIComponent(file.name) + "?t=" + new Date().getTime();
- thumbnail = `

`;
+ const imageUrl = folderPath + encodeURIComponent(file.name) + "?t=" + Date.now();
+ thumbnail = `

`;
}
} else if (/\.(mp3|wav|m4a|ogg|flac|aac|wma|opus)$/i.test(file.name)) {
thumbnail = `
audiotrack`;
@@ -441,82 +500,127 @@ export function renderGalleryView(folder, container) {
thumbnail = `
insert_drive_file`;
}
+ // tag badges
let tagBadgesHTML = "";
- if (file.tags && file.tags.length > 0) {
+ if (file.tags && file.tags.length) {
tagBadgesHTML = `
`;
file.tags.forEach(tag => {
- tagBadgesHTML += `${escapeHTML(tag.name)}`;
+ tagBadgesHTML += `
+ ${escapeHTML(tag.name)}
+ `;
});
tagBadgesHTML += `
`;
}
+ // card with checkbox, preview, info, buttons
galleryHTML += `
-
-
+
+
+
+
+
${thumbnail}
-
-
${escapeHTML(file.name)}
+
+
+
+ ${escapeHTML(file.name)}
+
${tagBadgesHTML}
-
-
`;
+
+ `;
});
- galleryHTML += "
"; // End gallery container.
+ galleryHTML += `
`; // end gallery-container
+
+ // bottom controls
+ galleryHTML += buildBottomControls(itemsPerPage);
+
+ // render
fileListContent.innerHTML = galleryHTML;
- // Re-apply slider constraints for the newly rendered slider.
- updateSliderConstraints();
+ // ensure toggle button
createViewToggleButton();
- // Attach share button event listeners.
- document.querySelectorAll(".share-btn").forEach(btn => {
- btn.addEventListener("click", e => {
- e.stopPropagation();
- const fileName = btn.getAttribute("data-file");
- const file = fileData.find(f => f.name === fileName);
- if (file) {
- import('./filePreview.js').then(module => {
- module.openShareModal(file, folder);
- });
- }
- });
+
+ // attach listeners
+
+ // checkboxes
+ document.querySelectorAll(".file-checkbox").forEach(cb => {
+ cb.addEventListener("change", () => updateFileActionButtons());
});
- // --- Slider Event Listener ---
+ // slider
const slider = document.getElementById("galleryColumnsSlider");
if (slider) {
- slider.addEventListener("input", function () {
- const value = this.value;
- document.getElementById("galleryColumnsValue").textContent = value;
- window.galleryColumns = value;
- const galleryContainer = document.querySelector(".gallery-container");
- if (galleryContainer) {
- galleryContainer.style.gridTemplateColumns = `repeat(${value}, 1fr)`;
- }
- const newMaxHeight = getMaxImageHeight();
- document.querySelectorAll(".gallery-thumbnail").forEach(img => {
- img.style.maxHeight = newMaxHeight + "px";
- });
+ slider.addEventListener("input", () => {
+ const v = +slider.value;
+ document.getElementById("galleryColumnsValue").textContent = v;
+ window.galleryColumns = v;
+ document.querySelector(".gallery-container")
+ .style.gridTemplateColumns = `repeat(${v},1fr)`;
+ document.querySelectorAll(".gallery-thumbnail")
+ .forEach(img => img.style.maxHeight = getMaxImageHeight() + "px");
});
}
+
+ // pagination
+ window.changePage = newPage => {
+ window.currentPage = newPage;
+ if (window.viewMode === "gallery") renderGalleryView(folder);
+ else renderFileTable(folder);
+ };
+
+ // items per page
+ window.changeItemsPerPage = cnt => {
+ window.itemsPerPage = +cnt;
+ localStorage.setItem("itemsPerPage", cnt);
+ window.currentPage = 1;
+ if (window.viewMode === "gallery") renderGalleryView(folder);
+ else renderFileTable(folder);
+ };
+
+ // update toolbar buttons
+ updateFileActionButtons();
}
// Responsive slider constraints based on screen size.
@@ -638,12 +742,22 @@ export function canEditFile(fileName) {
// Expose global functions for pagination and preview.
window.changePage = function (newPage) {
window.currentPage = newPage;
- renderFileTable(window.currentFolder);
+ if (window.viewMode === 'gallery') {
+ renderGalleryView(window.currentFolder);
+ } else {
+ renderFileTable(window.currentFolder);
+ }
};
+
window.changeItemsPerPage = function (newCount) {
- window.itemsPerPage = parseInt(newCount);
+ window.itemsPerPage = parseInt(newCount, 10);
+ localStorage.setItem('itemsPerPage', newCount);
window.currentPage = 1;
- renderFileTable(window.currentFolder);
+ if (window.viewMode === 'gallery') {
+ renderGalleryView(window.currentFolder);
+ } else {
+ renderFileTable(window.currentFolder);
+ }
};
// fileListView.js (bottom)
diff --git a/public/js/fileTags.js b/public/js/fileTags.js
index 42442b9..6051c6a 100644
--- a/public/js/fileTags.js
+++ b/public/js/fileTags.js
@@ -5,6 +5,7 @@
// filtering the file list by tag, and persisting tag data.
import { escapeHTML } from './domUtils.js';
import { t } from './i18n.js';
+import { renderFileTable, renderGalleryView } from './fileListView.js';
export function openTagModal(file) {
// Create the modal element.
@@ -63,6 +64,11 @@ export function openTagModal(file) {
updateTagModalDisplay(file);
updateFileRowTagDisplay(file);
saveFileTags(file);
+ if (window.viewMode === 'gallery') {
+ renderGalleryView(window.currentFolder);
+ } else {
+ renderFileTable(window.currentFolder);
+ }
document.getElementById('tagNameInput').value = '';
updateCustomTagDropdown();
});
@@ -125,6 +131,11 @@ export function openMultiTagModal(files) {
saveFileTags(file);
});
modal.remove();
+ if (window.viewMode === 'gallery') {
+ renderGalleryView(window.currentFolder);
+ } else {
+ renderFileTable(window.currentFolder);
+ }
});
}