Merge pull request #263 from EdouardVanbelle/fix/select-all

This commit is contained in:
Dionisio Pozo
2026-04-05 10:09:13 +02:00
committed by GitHub
6 changed files with 44 additions and 59 deletions
+4 -17
View File
@@ -206,23 +206,11 @@ async function loadFiles(options = { insertHistory: true}) {
const listing = await response.json(); const listing = await response.json();
if (window.multiSelect) window.multiSelect.clear();
window.ui._items.clear(); window.ui._items.clear();
window.ui.resetFilesList();
const _t = (window.i18n && window.i18n.t) ? window.i18n.t : k => k.split('.').pop(); if (window.multiSelect) {
window.ui.showError(` window.multiSelect.clear();
<div class="list-header"> window.multiSelect.init(); // this will wire buttons & select-all-checkbox
<div class="list-header-checkbox"><input type="checkbox" id="select-all-checkbox" title="Select all"></div>
<div data-i18n="files.name">${_t('files.name')}</div>
<div data-i18n="files.type">${_t('files.type')}</div>
<div data-i18n="files.size">${_t('files.size')}</div>
<div data-i18n="files.modified">${_t('files.modified')}</div>
</div>`
);
const selectAllCb = document.getElementById('select-all-checkbox');
if (selectAllCb && window.multiSelect) {
selectAllCb.addEventListener('change', () => window.multiSelect.toggleAll());
} }
const folderList = Array.isArray(listing.folders) ? listing.folders : []; const folderList = Array.isArray(listing.folders) ? listing.folders : [];
@@ -231,7 +219,6 @@ async function loadFiles(options = { insertHistory: true}) {
if (folderList.length === 0 && fileList.length === 0) { if (folderList.length === 0 && fileList.length === 0) {
window.ui.showEmptyList(); window.ui.showEmptyList();
} else { } else {
window.ui.resetFilesList();
window.ui.renderFolders(folderList); window.ui.renderFolders(folderList);
window.ui.renderFiles(fileList); window.ui.renderFiles(fileList);
} }
+8 -1
View File
@@ -892,6 +892,12 @@ const ui = {
return; return;
} }
// shiftkey is used to complete selection
if (e.shiftKey && window.multiSelect) {
window.multiSelect.handleToggleItem(card, e);
return;
}
if (info.type === 'folder') { if (info.type === 'folder') {
navigateFolder(card); navigateFolder(card);
} else { } else {
@@ -1225,6 +1231,7 @@ const ui = {
const filesContainerError=document.getElementById("files-container-error"); const filesContainerError=document.getElementById("files-container-error");
if (!filesList) return; if (!filesList) return;
filesList.innerHTML=` filesList.innerHTML=`
<div class="list-header"> <div class="list-header">
<div class="list-header-checkbox"><input type="checkbox" id="select-all-checkbox" title="Select all"></div> <div class="list-header-checkbox"><input type="checkbox" id="select-all-checkbox" title="Select all"></div>
@@ -1350,7 +1357,7 @@ const ui = {
*/ */
function toggleCardSelection(card, event) { function toggleCardSelection(card, event) {
if (window.multiSelect) { if (window.multiSelect) {
window.multiSelect.handleItemClick(card, event); window.multiSelect.handleToggleItem(card, event);
} else { } else {
card.classList.toggle('selected'); card.classList.toggle('selected');
} }
+28 -17
View File
@@ -9,6 +9,8 @@
// TODO: rename into selection-bar ? // TODO: rename into selection-bar ?
// TODO: merge with photo part // TODO: merge with photo part
// @ts-check
const multiSelect = { const multiSelect = {
/** Currently selected items: Map<id, { id, name, type, parentId }> */ /** Currently selected items: Map<id, { id, name, type, parentId }> */
_selected: new Map(), _selected: new Map(),
@@ -162,17 +164,12 @@ const multiSelect = {
// ── Click handler (shared by grid + list) ─────────────── // ── Click handler (shared by grid + list) ───────────────
handleItemClick(el, event) { handleToggleItem(el, event) {
const items = this._getAllVisibleItems(); const items = this._getAllVisibleItems();
const index = items.indexOf(el); const index = items.indexOf(el);
const info = this._extractInfo(el); const info = this._extractInfo(el);
if (!info) return; if (!info) return;
const selectorOther = info.type === 'folder'
? `[data-folder-id="${info.id}"]`
: `[data-file-id="${info.id}"]`;
const otherEl = [...document.querySelectorAll(selectorOther)].find(e => e !== el);
if (event && event.shiftKey && this._lastClickedIndex >= 0 && index >= 0) { if (event && event.shiftKey && this._lastClickedIndex >= 0 && index >= 0) {
const start = Math.min(this._lastClickedIndex, index); const start = Math.min(this._lastClickedIndex, index);
const end = Math.max(this._lastClickedIndex, index); const end = Math.max(this._lastClickedIndex, index);
@@ -183,16 +180,24 @@ const multiSelect = {
const sel = iInfo.type === 'folder' const sel = iInfo.type === 'folder'
? `[data-folder-id="${iInfo.id}"]` ? `[data-folder-id="${iInfo.id}"]`
: `[data-file-id="${iInfo.id}"]`; : `[data-file-id="${iInfo.id}"]`;
document.querySelectorAll(sel).forEach(e => e.classList.add('selected')); document.querySelectorAll(sel).forEach((e) => {
e.classList.add('selected');
let checkbox = e.querySelector('input[type="checkbox"]');
if (checkbox)
checkbox.checked = true;
});
} }
} }
} else { } else {
const nowSelected = this.toggle(info.id, info.name, info.type, info.parentId); const nowSelected = this.toggle(info.id, info.name, info.type, info.parentId);
el.classList.toggle('selected', nowSelected); el.classList.toggle('selected', nowSelected);
if (otherEl) otherEl.classList.toggle('selected', nowSelected); let checkbox = el.querySelector('input[type="checkbox"]');
if (checkbox)
checkbox.checked = nowSelected;
} }
this._lastClickedIndex = index; this._lastClickedIndex = index;
this._syncUI(); this._syncUI();
this._syncSelectAllCheckbox();
}, },
// ── Selection bar (replaces list-header when items selected) ──── // ── Selection bar (replaces list-header when items selected) ────
@@ -481,15 +486,19 @@ const multiSelect = {
document.addEventListener('keydown', (e) => { document.addEventListener('keydown', (e) => {
if (e.target.closest('input, textarea, [contenteditable], .rename-dialog, .share-dialog, .confirm-dialog')) return; if (e.target.closest('input, textarea, [contenteditable], .rename-dialog, .share-dialog, .confirm-dialog')) return;
const selectAllCheckbox = document.getElementById('select-all-checkbox');
// ctrl+a cmd+a // ctrl+a cmd+a
if ((e.ctrlKey || e.metaKey) && e.key === 'a') { if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
const filesList = document.getElementById('files-list'); if (selectAllCheckbox)
if (filesList && filesList.closest('.files-container')) { selectAllCheckbox.checked = true;
e.preventDefault(); this.selectAll();
this.selectAll(); e.preventDefault();
} }
if (e.key === 'Escape' && this.hasSelection) {
this.clear();
if (selectAllCheckbox)
selectAllCheckbox.checked = false;
} }
if (e.key === 'Escape' && this.hasSelection) this.clear();
if (e.key === 'Delete' && this.hasSelection) this.batchDelete(); if (e.key === 'Delete' && this.hasSelection) this.batchDelete();
}); });
@@ -503,10 +512,12 @@ const multiSelect = {
}, },
// FIXME: competition with _
_injectListHeaderCheckbox() { _injectListHeaderCheckbox() {
const cb = document.getElementById('select-all-checkbox'); const self = this;
if (!cb) return; const selectAllCheckbox = document.getElementById('select-all-checkbox');
cb.addEventListener('change', () => this.toggleAll()); if (!selectAllCheckbox) return;
selectAllCheckbox.addEventListener('change', () => self.toggleAll());
}, },
}; };
-12
View File
@@ -106,18 +106,6 @@ const search = {
window.ui.resetFilesList(); // ensure also list visible & error hidden window.ui.resetFilesList(); // ensure also list visible & error hidden
const filesList = document.getElementById('files-list'); const filesList = document.getElementById('files-list');
// reset list
filesList.innerHTML = `
<div class="list-header">
<div class="list-header-checkbox"><input type="checkbox" id="select-all-checkbox" title="Select all"></div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="files.size">Size</div>
<div data-i18n="files.modified">Modified</div>
<div></div>
</div>
`;
// Search results header with query time and sort controls // Search results header with query time and sort controls
const totalCount = results.total_count || (results.files.length + results.folders.length); const totalCount = results.total_count || (results.files.length + results.folders.length);
const queryTimeText = results.query_time_ms !== undefined const queryTimeText = results.query_time_ms !== undefined
-12
View File
@@ -168,18 +168,6 @@ const favorites = {
} }
window.ui.resetFilesList(); // ensure also list visible & error hidden window.ui.resetFilesList(); // ensure also list visible & error hidden
const filesList = document.getElementById('files-list');
filesList.innerHTML = `
<div class="list-header">
<div class="list-header-checkbox"><input type="checkbox" id="select-all-checkbox" title="Select all"></div>
<div data-i18n="files.name">Name</div>
<div data-i18n="files.type">Type</div>
<div data-i18n="files.size">Size</div>
<div data-i18n="files.modified">Modified</div>
</div>
`;
window.ui.updateBreadcrumb(''); window.ui.updateBreadcrumb('');
if (this._cache.size === 0) { if (this._cache.size === 0) {
+4
View File
@@ -100,6 +100,10 @@ const recent = {
</div> </div>
`; `;
if (window.multiSelect) {
window.multiSelect.clear();
window.multiSelect.init(); // this will wire buttons & select-all-checkbox
}
window.ui.updateBreadcrumb(''); window.ui.updateBreadcrumb('');
if (recentItems.length === 0) { if (recentItems.length === 0) {