aktueller stand
This commit is contained in:
481
web/app.js
481
web/app.js
@@ -300,6 +300,14 @@ const includeExpiredToggle = document.getElementById('includeExpiredToggle');
|
||||
const mergeControls = document.getElementById('mergeControls');
|
||||
const mergeModeToggle = document.getElementById('mergeModeToggle');
|
||||
const mergeSubmitBtn = document.getElementById('mergeSubmitBtn');
|
||||
const pendingBulkControls = document.getElementById('pendingBulkControls');
|
||||
const pendingBulkCountSelect = document.getElementById('pendingBulkCountSelect');
|
||||
const pendingBulkOpenBtn = document.getElementById('pendingBulkOpenBtn');
|
||||
const pendingAutoOpenToggle = document.getElementById('pendingAutoOpenToggle');
|
||||
const pendingAutoOpenOverlay = document.getElementById('pendingAutoOpenOverlay');
|
||||
const pendingAutoOpenOverlayPanel = document.getElementById('pendingAutoOpenOverlayPanel');
|
||||
const pendingAutoOpenCountdown = document.getElementById('pendingAutoOpenCountdown');
|
||||
const pendingBulkStatus = document.getElementById('pendingBulkStatus');
|
||||
|
||||
const REFRESH_SETTINGS_KEY = 'trackerRefreshSettings';
|
||||
const SORT_SETTINGS_KEY = 'trackerSortSettings';
|
||||
@@ -313,6 +321,12 @@ const BOOKMARK_WINDOW_DAYS = 28;
|
||||
const BOOKMARK_SUFFIXES = ['Gewinnspiel', 'gewinnen', 'verlosen'];
|
||||
const BOOKMARK_PREFS_KEY = 'trackerBookmarkPreferences';
|
||||
const INCLUDE_EXPIRED_STORAGE_KEY = 'trackerIncludeExpired';
|
||||
const PENDING_BULK_COUNT_STORAGE_KEY = 'trackerPendingBulkCount';
|
||||
const PENDING_AUTO_OPEN_STORAGE_KEY = 'trackerPendingAutoOpen';
|
||||
const DEFAULT_PENDING_BULK_COUNT = 5;
|
||||
const PENDING_AUTO_OPEN_DELAY_MS = 1500;
|
||||
const PENDING_OPEN_COOLDOWN_STORAGE_KEY = 'trackerPendingOpenCooldown';
|
||||
const PENDING_OPEN_COOLDOWN_MS = 40 * 60 * 1000;
|
||||
|
||||
function loadIncludeExpiredPreference() {
|
||||
try {
|
||||
@@ -337,6 +351,110 @@ function persistIncludeExpiredPreference(value) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPendingOpenCooldownStorageKey(profileNumber = currentProfile) {
|
||||
const safeProfile = profileNumber || currentProfile || 1;
|
||||
return `${PENDING_OPEN_COOLDOWN_STORAGE_KEY}:${safeProfile}`;
|
||||
}
|
||||
|
||||
function loadPendingOpenCooldownMap(profileNumber = currentProfile) {
|
||||
const storageKey = getPendingOpenCooldownStorageKey(profileNumber);
|
||||
try {
|
||||
const raw = localStorage.getItem(storageKey);
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
const now = Date.now();
|
||||
const cleaned = {};
|
||||
Object.entries(parsed).forEach(([id, timestamp]) => {
|
||||
const value = Number(timestamp);
|
||||
if (Number.isFinite(value) && now - value < PENDING_OPEN_COOLDOWN_MS) {
|
||||
cleaned[id] = value;
|
||||
}
|
||||
});
|
||||
if (Object.keys(cleaned).length !== Object.keys(parsed).length) {
|
||||
localStorage.setItem(storageKey, JSON.stringify(cleaned));
|
||||
}
|
||||
return cleaned;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Konnte Cooldown-Daten für offene Beiträge nicht laden:', error);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
function persistPendingOpenCooldownMap(profileNumber, map) {
|
||||
const storageKey = getPendingOpenCooldownStorageKey(profileNumber);
|
||||
try {
|
||||
localStorage.setItem(storageKey, JSON.stringify(map || {}));
|
||||
} catch (error) {
|
||||
console.warn('Konnte Cooldown-Daten für offene Beiträge nicht speichern:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function isPendingOpenCooldownActive(postId) {
|
||||
if (!postId) {
|
||||
return false;
|
||||
}
|
||||
const timestamp = pendingOpenCooldownMap[postId];
|
||||
if (!timestamp) {
|
||||
return false;
|
||||
}
|
||||
const elapsed = Date.now() - timestamp;
|
||||
if (elapsed < PENDING_OPEN_COOLDOWN_MS) {
|
||||
return true;
|
||||
}
|
||||
delete pendingOpenCooldownMap[postId];
|
||||
persistPendingOpenCooldownMap(currentProfile, pendingOpenCooldownMap);
|
||||
return false;
|
||||
}
|
||||
|
||||
function recordPendingOpen(postId) {
|
||||
if (!postId) {
|
||||
return;
|
||||
}
|
||||
pendingOpenCooldownMap[postId] = Date.now();
|
||||
persistPendingOpenCooldownMap(currentProfile, pendingOpenCooldownMap);
|
||||
}
|
||||
|
||||
function loadPendingBulkCount() {
|
||||
try {
|
||||
const stored = localStorage.getItem(PENDING_BULK_COUNT_STORAGE_KEY);
|
||||
const value = parseInt(stored, 10);
|
||||
if (!Number.isNaN(value) && [1, 5, 10, 15, 20].includes(value)) {
|
||||
return value;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bulk-Anzahl für offene Beiträge nicht laden:', error);
|
||||
}
|
||||
return DEFAULT_PENDING_BULK_COUNT;
|
||||
}
|
||||
|
||||
function persistPendingBulkCount(value) {
|
||||
try {
|
||||
localStorage.setItem(PENDING_BULK_COUNT_STORAGE_KEY, String(value));
|
||||
} catch (error) {
|
||||
console.warn('Konnte Bulk-Anzahl für offene Beiträge nicht speichern:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function loadPendingAutoOpenEnabled() {
|
||||
try {
|
||||
return localStorage.getItem(PENDING_AUTO_OPEN_STORAGE_KEY) === '1';
|
||||
} catch (error) {
|
||||
console.warn('Konnte Auto-Öffnen-Status nicht laden:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function persistPendingAutoOpenEnabled(enabled) {
|
||||
try {
|
||||
localStorage.setItem(PENDING_AUTO_OPEN_STORAGE_KEY, enabled ? '1' : '0');
|
||||
} catch (error) {
|
||||
console.warn('Konnte Auto-Öffnen-Status nicht speichern:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateIncludeExpiredToggleUI() {
|
||||
if (!includeExpiredToggle) {
|
||||
return;
|
||||
@@ -345,6 +463,13 @@ function updateIncludeExpiredToggleUI() {
|
||||
}
|
||||
|
||||
includeExpiredPosts = loadIncludeExpiredPreference();
|
||||
let pendingBulkCount = loadPendingBulkCount();
|
||||
let pendingAutoOpenEnabled = loadPendingAutoOpenEnabled();
|
||||
let pendingAutoOpenTriggered = false;
|
||||
let pendingAutoOpenTimerId = null;
|
||||
let pendingAutoOpenCountdownIntervalId = null;
|
||||
let pendingProcessingBatch = false;
|
||||
let pendingOpenCooldownMap = loadPendingOpenCooldownMap(currentProfile);
|
||||
|
||||
function updateIncludeExpiredToggleVisibility() {
|
||||
if (!includeExpiredToggle) {
|
||||
@@ -388,6 +513,26 @@ function updateMergeControlsUI() {
|
||||
}
|
||||
}
|
||||
|
||||
function updatePendingBulkControls(filteredCount = 0) {
|
||||
if (!pendingBulkControls) {
|
||||
return;
|
||||
}
|
||||
const isPendingTab = currentTab === 'pending';
|
||||
pendingBulkControls.hidden = !isPendingTab;
|
||||
pendingBulkControls.style.display = isPendingTab ? 'flex' : 'none';
|
||||
if (pendingBulkOpenBtn) {
|
||||
pendingBulkOpenBtn.disabled = !isPendingTab || pendingProcessingBatch || filteredCount === 0;
|
||||
}
|
||||
}
|
||||
|
||||
function setPendingBulkStatus(message = '', isError = false) {
|
||||
if (!pendingBulkStatus) {
|
||||
return;
|
||||
}
|
||||
pendingBulkStatus.textContent = message || '';
|
||||
pendingBulkStatus.classList.toggle('bulk-status--error', !!isError);
|
||||
}
|
||||
|
||||
function initializeFocusParams() {
|
||||
try {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
@@ -1635,6 +1780,16 @@ function updateSortDirectionToggleUI() {
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaultSortDirectionForMode(mode) {
|
||||
if (mode === 'deadline') {
|
||||
return 'asc';
|
||||
}
|
||||
if (mode === 'smart') {
|
||||
return 'desc';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function normalizeRequiredProfiles(post) {
|
||||
if (Array.isArray(post.required_profiles) && post.required_profiles.length) {
|
||||
return post.required_profiles
|
||||
@@ -1714,6 +1869,224 @@ function updateFilteredCount(tab, count) {
|
||||
tabFilteredCounts[key] = Math.max(0, count || 0);
|
||||
}
|
||||
|
||||
function getPostListState() {
|
||||
const postItems = posts.map((post) => ({
|
||||
post,
|
||||
status: computePostStatus(post)
|
||||
}));
|
||||
|
||||
const sortedItems = [...postItems].sort(comparePostItems);
|
||||
let filteredItems = sortedItems;
|
||||
|
||||
if (currentTab === 'pending') {
|
||||
filteredItems = sortedItems.filter((item) => !item.status.isExpired && item.status.canCurrentProfileCheck && !item.status.isComplete);
|
||||
} else {
|
||||
filteredItems = includeExpiredPosts
|
||||
? sortedItems
|
||||
: sortedItems.filter((item) => !item.status.isExpired && !item.status.isComplete);
|
||||
}
|
||||
|
||||
const tabTotalCount = filteredItems.length;
|
||||
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const searchValue = searchInput && typeof searchInput.value === 'string' ? searchInput.value.trim() : '';
|
||||
const searchActive = Boolean(searchValue);
|
||||
|
||||
if (searchActive) {
|
||||
const searchTerm = searchValue.toLowerCase();
|
||||
filteredItems = filteredItems.filter((item) => {
|
||||
const post = item.post;
|
||||
return (
|
||||
(post.title && post.title.toLowerCase().includes(searchTerm)) ||
|
||||
(post.url && post.url.toLowerCase().includes(searchTerm)) ||
|
||||
(post.created_by_name && post.created_by_name.toLowerCase().includes(searchTerm)) ||
|
||||
(post.id && post.id.toLowerCase().includes(searchTerm))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
sortedItems,
|
||||
filteredItems,
|
||||
tabTotalCount,
|
||||
searchActive,
|
||||
searchValue
|
||||
};
|
||||
}
|
||||
|
||||
function clearPendingAutoOpenCountdown() {
|
||||
if (pendingAutoOpenCountdownIntervalId) {
|
||||
clearInterval(pendingAutoOpenCountdownIntervalId);
|
||||
pendingAutoOpenCountdownIntervalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePendingAutoOpenCountdownLabel(remainingMs) {
|
||||
if (!pendingAutoOpenCountdown) {
|
||||
return;
|
||||
}
|
||||
const safeMs = Math.max(0, remainingMs);
|
||||
const seconds = safeMs / 1000;
|
||||
const formatted = seconds >= 10 ? seconds.toFixed(0) : seconds.toFixed(1);
|
||||
pendingAutoOpenCountdown.textContent = formatted;
|
||||
}
|
||||
|
||||
function hidePendingAutoOpenOverlay() {
|
||||
clearPendingAutoOpenCountdown();
|
||||
if (pendingAutoOpenOverlay) {
|
||||
pendingAutoOpenOverlay.classList.remove('visible');
|
||||
pendingAutoOpenOverlay.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function showPendingAutoOpenOverlay(delayMs) {
|
||||
if (!pendingAutoOpenOverlay) {
|
||||
return;
|
||||
}
|
||||
const duration = Math.max(0, delayMs);
|
||||
hidePendingAutoOpenOverlay();
|
||||
pendingAutoOpenOverlay.hidden = false;
|
||||
requestAnimationFrame(() => pendingAutoOpenOverlay.classList.add('visible'));
|
||||
updatePendingAutoOpenCountdownLabel(duration);
|
||||
const start = Date.now();
|
||||
pendingAutoOpenCountdownIntervalId = setInterval(() => {
|
||||
const remaining = Math.max(0, duration - (Date.now() - start));
|
||||
updatePendingAutoOpenCountdownLabel(remaining);
|
||||
if (remaining <= 0) {
|
||||
clearPendingAutoOpenCountdown();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function cancelPendingAutoOpen(showMessage = false) {
|
||||
if (pendingAutoOpenTimerId) {
|
||||
clearTimeout(pendingAutoOpenTimerId);
|
||||
pendingAutoOpenTimerId = null;
|
||||
}
|
||||
pendingAutoOpenTriggered = false;
|
||||
hidePendingAutoOpenOverlay();
|
||||
if (showMessage) {
|
||||
setPendingBulkStatus('Automatisches Öffnen abgebrochen.', false);
|
||||
}
|
||||
}
|
||||
|
||||
function getPendingVisibleCandidates() {
|
||||
if (currentTab !== 'pending') {
|
||||
return { items: [], totalVisible: 0, cooldownBlocked: 0 };
|
||||
}
|
||||
const { filteredItems } = getPostListState();
|
||||
const visibleCount = Math.min(filteredItems.length, getVisibleCount(currentTab));
|
||||
const visibleItems = filteredItems
|
||||
.slice(0, visibleCount)
|
||||
.filter(({ post }) => post && post.url);
|
||||
const items = visibleItems.filter(({ post }) => !isPendingOpenCooldownActive(post.id));
|
||||
const cooldownBlocked = Math.max(0, visibleItems.length - items.length);
|
||||
return { items, totalVisible: visibleItems.length, cooldownBlocked };
|
||||
}
|
||||
|
||||
function openPendingBatch({ auto = false } = {}) {
|
||||
if (pendingProcessingBatch) {
|
||||
return;
|
||||
}
|
||||
if (!auto) {
|
||||
cancelPendingAutoOpen(false);
|
||||
}
|
||||
const { items: candidates, totalVisible, cooldownBlocked } = getPendingVisibleCandidates();
|
||||
if (!candidates.length) {
|
||||
if (!auto) {
|
||||
if (totalVisible === 0) {
|
||||
setPendingBulkStatus('Keine offenen Beiträge zum Öffnen.', true);
|
||||
} else if (cooldownBlocked > 0) {
|
||||
setPendingBulkStatus('Alle sichtbaren Beiträge sind noch im Cooldown (40 min).', true);
|
||||
} else {
|
||||
setPendingBulkStatus('Keine offenen Beiträge zum Öffnen.', true);
|
||||
}
|
||||
}
|
||||
pendingAutoOpenTriggered = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const count = pendingBulkCount || DEFAULT_PENDING_BULK_COUNT;
|
||||
const selection = candidates.slice(0, count);
|
||||
|
||||
pendingProcessingBatch = true;
|
||||
if (pendingBulkOpenBtn) {
|
||||
pendingBulkOpenBtn.disabled = true;
|
||||
}
|
||||
if (!auto) {
|
||||
setPendingBulkStatus('');
|
||||
} else {
|
||||
setPendingBulkStatus(`Öffne automatisch ${selection.length} Links...`, false);
|
||||
}
|
||||
|
||||
selection.forEach(({ post }) => {
|
||||
if (post && post.url) {
|
||||
window.open(post.url, '_blank', 'noopener');
|
||||
recordPendingOpen(post.id);
|
||||
}
|
||||
});
|
||||
|
||||
pendingProcessingBatch = false;
|
||||
if (pendingBulkOpenBtn) {
|
||||
pendingBulkOpenBtn.disabled = false;
|
||||
}
|
||||
if (auto) {
|
||||
setPendingBulkStatus('');
|
||||
pendingAutoOpenTriggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
function maybeAutoOpenPending(reason = '', delayMs = PENDING_AUTO_OPEN_DELAY_MS) {
|
||||
if (!isPostsViewActive()) {
|
||||
hidePendingAutoOpenOverlay();
|
||||
return;
|
||||
}
|
||||
if (currentTab !== 'pending') {
|
||||
hidePendingAutoOpenOverlay();
|
||||
return;
|
||||
}
|
||||
if (!pendingAutoOpenEnabled) {
|
||||
hidePendingAutoOpenOverlay();
|
||||
return;
|
||||
}
|
||||
if (pendingProcessingBatch) {
|
||||
return;
|
||||
}
|
||||
if (pendingAutoOpenTriggered) {
|
||||
return;
|
||||
}
|
||||
const { items: candidates } = getPendingVisibleCandidates();
|
||||
if (!candidates.length) {
|
||||
hidePendingAutoOpenOverlay();
|
||||
return;
|
||||
}
|
||||
if (pendingAutoOpenTimerId) {
|
||||
clearTimeout(pendingAutoOpenTimerId);
|
||||
pendingAutoOpenTimerId = null;
|
||||
}
|
||||
hidePendingAutoOpenOverlay();
|
||||
pendingAutoOpenTriggered = true;
|
||||
const delay = typeof delayMs === 'number' ? Math.max(0, delayMs) : PENDING_AUTO_OPEN_DELAY_MS;
|
||||
if (delay === 0) {
|
||||
if (pendingAutoOpenEnabled) {
|
||||
openPendingBatch({ auto: true });
|
||||
} else {
|
||||
pendingAutoOpenTriggered = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
showPendingAutoOpenOverlay(delay);
|
||||
pendingAutoOpenTimerId = setTimeout(() => {
|
||||
pendingAutoOpenTimerId = null;
|
||||
hidePendingAutoOpenOverlay();
|
||||
if (pendingAutoOpenEnabled) {
|
||||
openPendingBatch({ auto: true });
|
||||
} else {
|
||||
pendingAutoOpenTriggered = false;
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function cleanupLoadMoreObserver() {
|
||||
if (loadMoreObserver && observedLoadMoreElement) {
|
||||
loadMoreObserver.unobserve(observedLoadMoreElement);
|
||||
@@ -1828,6 +2201,7 @@ function setTab(tab, { updateUrl = true } = {}) {
|
||||
updateTabInUrl();
|
||||
}
|
||||
renderPosts();
|
||||
maybeAutoOpenPending('tab');
|
||||
}
|
||||
|
||||
function initializeTabFromUrl() {
|
||||
@@ -3011,7 +3385,9 @@ function applyProfileNumber(profileNumber, { fromBackend = false } = {}) {
|
||||
}
|
||||
|
||||
resetVisibleCount();
|
||||
pendingOpenCooldownMap = loadPendingOpenCooldownMap(currentProfile);
|
||||
renderPosts();
|
||||
maybeAutoOpenPending('profile');
|
||||
}
|
||||
|
||||
// Load profile from localStorage
|
||||
@@ -3066,6 +3442,42 @@ if (includeExpiredToggle) {
|
||||
});
|
||||
}
|
||||
|
||||
if (pendingBulkCountSelect) {
|
||||
pendingBulkCountSelect.value = String(pendingBulkCount);
|
||||
pendingBulkCountSelect.addEventListener('change', () => {
|
||||
const value = parseInt(pendingBulkCountSelect.value, 10);
|
||||
if (!Number.isNaN(value)) {
|
||||
pendingBulkCount = value;
|
||||
persistPendingBulkCount(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pendingBulkOpenBtn) {
|
||||
pendingBulkOpenBtn.addEventListener('click', () => openPendingBatch());
|
||||
}
|
||||
|
||||
if (pendingAutoOpenOverlayPanel) {
|
||||
pendingAutoOpenOverlayPanel.addEventListener('click', () => cancelPendingAutoOpen(true));
|
||||
}
|
||||
|
||||
if (pendingAutoOpenToggle) {
|
||||
pendingAutoOpenToggle.checked = !!pendingAutoOpenEnabled;
|
||||
pendingAutoOpenToggle.addEventListener('change', () => {
|
||||
pendingAutoOpenEnabled = pendingAutoOpenToggle.checked;
|
||||
persistPendingAutoOpenEnabled(pendingAutoOpenEnabled);
|
||||
pendingAutoOpenTriggered = false;
|
||||
if (!pendingAutoOpenEnabled && pendingAutoOpenTimerId) {
|
||||
cancelPendingAutoOpen(false);
|
||||
}
|
||||
if (pendingAutoOpenEnabled) {
|
||||
maybeAutoOpenPending('toggle');
|
||||
} else {
|
||||
hidePendingAutoOpenOverlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Tab switching
|
||||
document.querySelectorAll('.tab-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
@@ -3164,6 +3576,11 @@ if (sortModeSelect) {
|
||||
sortModeSelect.addEventListener('change', () => {
|
||||
const value = sortModeSelect.value;
|
||||
sortMode = VALID_SORT_MODES.has(value) ? value : DEFAULT_SORT_SETTINGS.mode;
|
||||
const defaultDirection = getDefaultSortDirectionForMode(sortMode);
|
||||
if (defaultDirection) {
|
||||
sortDirection = defaultDirection;
|
||||
updateSortDirectionToggleUI();
|
||||
}
|
||||
saveSortMode();
|
||||
resetVisibleCount();
|
||||
renderPosts();
|
||||
@@ -3201,6 +3618,7 @@ async function fetchPosts({ showLoader = true } = {}) {
|
||||
}
|
||||
|
||||
isFetchingPosts = true;
|
||||
cancelPendingAutoOpen(false);
|
||||
|
||||
try {
|
||||
if (showLoader) {
|
||||
@@ -3218,6 +3636,7 @@ async function fetchPosts({ showLoader = true } = {}) {
|
||||
await normalizeLoadedPostUrls();
|
||||
sortPostsByCreatedAt();
|
||||
renderPosts();
|
||||
maybeAutoOpenPending('load');
|
||||
} catch (error) {
|
||||
if (showLoader) {
|
||||
showError('Fehler beim Laden der Beiträge. Stelle sicher, dass das Backend läuft.');
|
||||
@@ -3487,45 +3906,18 @@ function renderPosts() {
|
||||
updateTabButtons();
|
||||
cleanupLoadMoreObserver();
|
||||
|
||||
const postItems = posts.map((post) => ({
|
||||
post,
|
||||
status: computePostStatus(post)
|
||||
}));
|
||||
const {
|
||||
sortedItems,
|
||||
filteredItems: filteredItemsResult,
|
||||
tabTotalCount,
|
||||
searchActive
|
||||
} = getPostListState();
|
||||
|
||||
const sortedItems = [...postItems].sort(comparePostItems);
|
||||
let filteredItems = filteredItemsResult;
|
||||
const focusCandidateEntry = (!focusHandled && (focusPostIdParam || focusNormalizedUrl))
|
||||
? sortedItems.find((item) => doesPostMatchFocus(item.post))
|
||||
: null;
|
||||
|
||||
let filteredItems = sortedItems;
|
||||
|
||||
if (currentTab === 'pending') {
|
||||
filteredItems = sortedItems.filter((item) => !item.status.isExpired && item.status.canCurrentProfileCheck && !item.status.isComplete);
|
||||
} else {
|
||||
filteredItems = includeExpiredPosts
|
||||
? sortedItems
|
||||
: sortedItems.filter((item) => !item.status.isExpired && !item.status.isComplete);
|
||||
}
|
||||
|
||||
const tabTotalCount = filteredItems.length;
|
||||
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const searchValue = searchInput && typeof searchInput.value === 'string' ? searchInput.value.trim() : '';
|
||||
const searchActive = Boolean(searchValue);
|
||||
|
||||
if (searchActive) {
|
||||
const searchTerm = searchValue.toLowerCase();
|
||||
filteredItems = filteredItems.filter((item) => {
|
||||
const post = item.post;
|
||||
return (
|
||||
(post.title && post.title.toLowerCase().includes(searchTerm)) ||
|
||||
(post.url && post.url.toLowerCase().includes(searchTerm)) ||
|
||||
(post.created_by_name && post.created_by_name.toLowerCase().includes(searchTerm)) ||
|
||||
(post.id && post.id.toLowerCase().includes(searchTerm))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (!focusHandled && focusCandidateEntry && !searchActive) {
|
||||
const candidateVisibleInCurrentTab = filteredItems.some(({ post }) => doesPostMatchFocus(post));
|
||||
if (!candidateVisibleInCurrentTab) {
|
||||
@@ -3554,6 +3946,7 @@ function renderPosts() {
|
||||
}
|
||||
|
||||
updateFilteredCount(currentTab, filteredItems.length);
|
||||
updatePendingBulkControls(filteredItems.length);
|
||||
|
||||
const visibleCount = Math.min(filteredItems.length, getVisibleCount(currentTab));
|
||||
const visibleItems = filteredItems.slice(0, visibleCount);
|
||||
@@ -4597,6 +4990,26 @@ window.addEventListener('resize', () => {
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('app:view-change', (event) => {
|
||||
const view = event && event.detail ? event.detail.view : null;
|
||||
if (view === 'posts') {
|
||||
maybeAutoOpenPending('view');
|
||||
} else {
|
||||
cancelPendingAutoOpen(false);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible' && pendingAutoOpenEnabled) {
|
||||
if (pendingAutoOpenTimerId) {
|
||||
clearTimeout(pendingAutoOpenTimerId);
|
||||
pendingAutoOpenTimerId = null;
|
||||
}
|
||||
pendingAutoOpenTriggered = false;
|
||||
maybeAutoOpenPending('visibility', PENDING_AUTO_OPEN_DELAY_MS);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize
|
||||
async function bootstrapApp() {
|
||||
const authenticated = await ensureAuthenticated();
|
||||
|
||||
Reference in New Issue
Block a user