Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 299d11c1d0 | |||
| 4d1f95cb1f |
+58
-6
@@ -751,6 +751,7 @@
|
|||||||
let mainItemsSentinel = null;
|
let mainItemsSentinel = null;
|
||||||
let mainItemsLoadingIndicator = null;
|
let mainItemsLoadingIndicator = null;
|
||||||
let mainItemsScrollPrefetchBound = false;
|
let mainItemsScrollPrefetchBound = false;
|
||||||
|
let cardVirtualizationObserver = null;
|
||||||
|
|
||||||
function ensureMainItemsLoadingIndicator() {
|
function ensureMainItemsLoadingIndicator() {
|
||||||
const itemsContainer = document.querySelector('#items-container');
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
@@ -1189,6 +1190,55 @@
|
|||||||
mainItemsScrollPrefetchBound = true;
|
mainItemsScrollPrefetchBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup DOM virtualization for items
|
||||||
|
if (!cardVirtualizationObserver) {
|
||||||
|
cardVirtualizationObserver = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
const card = entry.target;
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
if (card.dataset.deloaded === 'true') {
|
||||||
|
card.innerHTML = card.dataset.savedHtml;
|
||||||
|
card.dataset.deloaded = 'false';
|
||||||
|
card.classList.remove('is-deloaded');
|
||||||
|
const favBtn = card.querySelector('.bookmark-btn');
|
||||||
|
if (favBtn) {
|
||||||
|
favBtn.addEventListener('click', (ev) => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
toggleFavorite(card.dataset.itemId, favBtn, card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const cardContent = card.querySelector('.card-content');
|
||||||
|
if (cardContent) {
|
||||||
|
cardContent.addEventListener('click', function(e) {
|
||||||
|
if (e.target.tagName === 'BUTTON' || e.target.tagName === 'A' || e.target.tagName === 'INPUT' ||
|
||||||
|
e.target.closest('button') || e.target.closest('a') || e.target.closest('.image-container')) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
openItemQuick(card.dataset.itemId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (card.dataset.deloaded !== 'true') {
|
||||||
|
const rect = card.getBoundingClientRect();
|
||||||
|
if (rect.height > 50) {
|
||||||
|
card.style.minHeight = rect.height + 'px';
|
||||||
|
card.dataset.itemId = card.querySelector('.card-content')?.dataset.itemId || '';
|
||||||
|
card.dataset.savedHtml = card.innerHTML;
|
||||||
|
card.innerHTML = '';
|
||||||
|
card.dataset.deloaded = 'true';
|
||||||
|
card.classList.add('is-deloaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
rootMargin: isMobileLayout ? '1500px 0px 1500px 0px' : '0px 2500px 0px 2500px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe all valid cards
|
||||||
|
document.querySelectorAll('.item-card').forEach(card => cardVirtualizationObserver.observe(card));
|
||||||
|
|
||||||
if (!mainItemsHasMore) return;
|
if (!mainItemsHasMore) return;
|
||||||
|
|
||||||
mainItemsObserver = new IntersectionObserver(entries => {
|
mainItemsObserver = new IntersectionObserver(entries => {
|
||||||
@@ -2419,29 +2469,29 @@
|
|||||||
// Add these functions right after the loadFilterState() function
|
// Add these functions right after the loadFilterState() function
|
||||||
|
|
||||||
function rebuildFilter3Options() {
|
function rebuildFilter3Options() {
|
||||||
if (!allItems || allItems.length === 0) return;
|
if (!allItems) return;
|
||||||
|
|
||||||
// Get current filter 1 and filter 2 selections
|
// Get current filter 1 and filter 2 selections
|
||||||
const filter1Selections = activeFilters.filter1;
|
const filter1Selections = activeFilters.filter1;
|
||||||
const filter2Selections = activeFilters.filter2;
|
const filter2Selections = activeFilters.filter2;
|
||||||
|
|
||||||
// If both filters are empty, show all filter3 values
|
// If both filters are empty, show all filter3 values from server
|
||||||
if (filter1Selections.length === 0 && filter2Selections.length === 0) {
|
if (filter1Selections.length === 0 && filter2Selections.length === 0) {
|
||||||
// Get all unique filter3 values
|
// Include dynamically added ones from loaded items too, just in case
|
||||||
const allFilter3Values = new Set();
|
const combinedFilter3Values = new Set(typeof allFilter3Values !== 'undefined' ? [...allFilter3Values] : []);
|
||||||
allItems.forEach(item => {
|
allItems.forEach(item => {
|
||||||
const filter3Array = Array.isArray(item.Filter3) ? item.Filter3 :
|
const filter3Array = Array.isArray(item.Filter3) ? item.Filter3 :
|
||||||
(item.Filter3 ? [item.Filter3] : []);
|
(item.Filter3 ? [item.Filter3] : []);
|
||||||
|
|
||||||
filter3Array.forEach(value => {
|
filter3Array.forEach(value => {
|
||||||
if (value && typeof value === 'string' && value.trim() !== '') {
|
if (value && typeof value === 'string' && value.trim() !== '') {
|
||||||
allFilter3Values.add(value);
|
combinedFilter3Values.add(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Populate filter 3 dropdown with all values
|
// Populate filter 3 dropdown with all values
|
||||||
populateFilterOptions('filter3-options', [...allFilter3Values].sort(), 3);
|
populateFilterOptions('filter3-options', [...combinedFilter3Values].sort(), 3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3114,6 +3164,8 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
content-visibility: auto;
|
||||||
|
contain-intrinsic-size: 300px 450px;
|
||||||
}
|
}
|
||||||
.item-card:hover {
|
.item-card:hover {
|
||||||
transform: translateY(-5px);
|
transform: translateY(-5px);
|
||||||
|
|||||||
@@ -403,6 +403,8 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s, box-shadow 0.2s;
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
content-visibility: auto;
|
||||||
|
contain-intrinsic-size: 300px 450px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-card.bulk-selected {
|
.item-card.bulk-selected {
|
||||||
@@ -2876,30 +2878,29 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rebuildFilter3Options() {
|
function rebuildFilter3Options() {
|
||||||
if (!allItems || allItems.length === 0) return;
|
if (!allItems) return;
|
||||||
|
|
||||||
// Get current filter 1 and filter 2 selections
|
// Get current filter 1 and filter 2 selections
|
||||||
const filter1Selections = activeFilters.filter1;
|
const filter1Selections = activeFilters.filter1;
|
||||||
const filter2Selections = activeFilters.filter2;
|
const filter2Selections = activeFilters.filter2;
|
||||||
|
|
||||||
// If both filters are empty, show all filter3 values
|
// If both filters are empty, show all filter3 values from server
|
||||||
if (filter1Selections.length === 0 && filter2Selections.length === 0) {
|
if (filter1Selections.length === 0 && filter2Selections.length === 0) {
|
||||||
// Get all unique filter3 values
|
// Include dynamically added ones from loaded items too, just in case
|
||||||
const allFilter3Values = new Set();
|
const combinedFilter3Values = new Set(typeof allFilter3Values !== 'undefined' ? [...allFilter3Values] : []);
|
||||||
allItems.forEach(item => {
|
allItems.forEach(item => {
|
||||||
const filter3Array = Array.isArray(item.Filter3) ? item.Filter3 :
|
const filter3Array = Array.isArray(item.Filter3) ? item.Filter3 :
|
||||||
(item.Filter3 ? [item.Filter3] : []);
|
(item.Filter3 ? [item.Filter3] : []);
|
||||||
|
|
||||||
filter3Array.forEach(value => {
|
filter3Array.forEach(value => {
|
||||||
if (value && typeof value === 'string' && value.trim() !== '') {
|
if (value && typeof value === 'string' && value.trim() !== '') {
|
||||||
allFilter3Values.add(value);
|
combinedFilter3Values.add(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Populate filter 3 dropdown with all values
|
// Populate filter 3 dropdown with all values
|
||||||
populateFilterOptions('filter3-options', [...allFilter3Values].sort(), 3);
|
populateFilterOptions('filter3-options', [...combinedFilter3Values].sort(), 3);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter items based on filter1 and filter2 selections
|
// Filter items based on filter1 and filter2 selections
|
||||||
@@ -3356,6 +3357,7 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
let mainAdminItemsLoadingIndicator = null;
|
let mainAdminItemsLoadingIndicator = null;
|
||||||
let mainAdminItemsScrollPrefetchBound = false;
|
let mainAdminItemsScrollPrefetchBound = false;
|
||||||
let totalItemsInSystem = 0;
|
let totalItemsInSystem = 0;
|
||||||
|
let cardVirtualizationObserver = null;
|
||||||
|
|
||||||
function ensureMainAdminItemsLoadingIndicator() {
|
function ensureMainAdminItemsLoadingIndicator() {
|
||||||
const itemsContainer = document.querySelector('#items-container');
|
const itemsContainer = document.querySelector('#items-container');
|
||||||
@@ -3783,6 +3785,56 @@ document.addEventListener('DOMContentLoaded', ()=>{
|
|||||||
mainAdminItemsScrollPrefetchBound = true;
|
mainAdminItemsScrollPrefetchBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup DOM virtualization for items
|
||||||
|
if (!cardVirtualizationObserver) {
|
||||||
|
cardVirtualizationObserver = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
const card = entry.target;
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
if (card.dataset.deloaded === 'true') {
|
||||||
|
card.innerHTML = card.dataset.savedHtml;
|
||||||
|
card.dataset.deloaded = 'false';
|
||||||
|
card.classList.remove('is-deloaded');
|
||||||
|
const favBtn = card.querySelector('.bookmark-btn');
|
||||||
|
if (favBtn) {
|
||||||
|
favBtn.addEventListener('click', (ev) => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
toggleFavorite(card.dataset.itemId, favBtn, card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const cardContent = card.querySelector('.card-content');
|
||||||
|
if (cardContent) {
|
||||||
|
cardContent.addEventListener('click', function(e) {
|
||||||
|
if (e.target.tagName === 'BUTTON' || e.target.tagName === 'A' || e.target.tagName === 'INPUT' ||
|
||||||
|
e.target.closest('button') || e.target.closest('a') || e.target.closest('.image-container') ||
|
||||||
|
e.target.closest('.bulk-delete-toggle') || e.target.closest('label')) return;
|
||||||
|
e.stopPropagation();
|
||||||
|
openItemQuick(card.dataset.itemId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (card.dataset.deloaded !== 'true') {
|
||||||
|
const rect = card.getBoundingClientRect();
|
||||||
|
if (rect.height > 50) {
|
||||||
|
card.style.minHeight = rect.height + 'px';
|
||||||
|
card.dataset.itemId = card.querySelector('.card-content')?.dataset.itemId || '';
|
||||||
|
card.dataset.savedHtml = card.innerHTML;
|
||||||
|
card.innerHTML = '';
|
||||||
|
card.dataset.deloaded = 'true';
|
||||||
|
card.classList.add('is-deloaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
rootMargin: isMobileLayout ? '1500px 0px 1500px 0px' : '0px 2500px 0px 2500px'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observe all valid cards
|
||||||
|
document.querySelectorAll('.item-card').forEach(card => cardVirtualizationObserver.observe(card));
|
||||||
|
|
||||||
if (!mainAdminItemsHasMore) return;
|
if (!mainAdminItemsHasMore) return;
|
||||||
|
|
||||||
mainAdminItemsObserver = new IntersectionObserver(entries => {
|
mainAdminItemsObserver = new IntersectionObserver(entries => {
|
||||||
|
|||||||
Reference in New Issue
Block a user