Aktueller Stand
This commit is contained in:
@@ -486,6 +486,49 @@ function getPostUrl(postElement, postNum = '?') {
|
||||
return { url: '', allCandidates: [] };
|
||||
}
|
||||
|
||||
function expandPhotoUrlHostVariants(url) {
|
||||
if (typeof url !== 'string' || !url) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
const hostname = parsed.hostname.toLowerCase();
|
||||
if (!hostname.endsWith('facebook.com')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const pathname = parsed.pathname.toLowerCase();
|
||||
if (!pathname.startsWith('/photo')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const search = parsed.search || '';
|
||||
const protocol = parsed.protocol || 'https:';
|
||||
const hosts = ['www.facebook.com', 'facebook.com', 'm.facebook.com'];
|
||||
const variants = [];
|
||||
|
||||
for (const candidateHost of hosts) {
|
||||
if (candidateHost === hostname) {
|
||||
continue;
|
||||
}
|
||||
const candidateUrl = `${protocol}//${candidateHost}${parsed.pathname}${search}`;
|
||||
const normalizedVariant = normalizeFacebookPostUrl(candidateUrl);
|
||||
if (
|
||||
normalizedVariant
|
||||
&& normalizedVariant !== url
|
||||
&& !variants.includes(normalizedVariant)
|
||||
) {
|
||||
variants.push(normalizedVariant);
|
||||
}
|
||||
}
|
||||
|
||||
return variants;
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Check if post is already tracked (checks all URL candidates to avoid duplicates)
|
||||
async function checkPostStatus(postUrl, allUrlCandidates = []) {
|
||||
try {
|
||||
@@ -507,13 +550,30 @@ async function checkPostStatus(postUrl, allUrlCandidates = []) {
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[FB Tracker] Checking post status for URLs:', urlsToCheck);
|
||||
const photoHostVariants = [];
|
||||
for (const candidateUrl of urlsToCheck) {
|
||||
const variants = expandPhotoUrlHostVariants(candidateUrl);
|
||||
for (const variant of variants) {
|
||||
if (!urlsToCheck.includes(variant) && !photoHostVariants.includes(variant)) {
|
||||
photoHostVariants.push(variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allUrlsToCheck = photoHostVariants.length
|
||||
? urlsToCheck.concat(photoHostVariants)
|
||||
: urlsToCheck;
|
||||
|
||||
if (photoHostVariants.length) {
|
||||
console.log('[FB Tracker] Added photo host variants for status check:', photoHostVariants);
|
||||
}
|
||||
console.log('[FB Tracker] Checking post status for URLs:', allUrlsToCheck);
|
||||
|
||||
let foundPost = null;
|
||||
let foundUrl = null;
|
||||
|
||||
// Check each URL
|
||||
for (const url of urlsToCheck) {
|
||||
for (const url of allUrlsToCheck) {
|
||||
const response = await backendFetch(`${API_URL}/posts/by-url?url=${encodeURIComponent(url)}`);
|
||||
|
||||
if (response.ok) {
|
||||
@@ -544,10 +604,14 @@ async function checkPostStatus(postUrl, allUrlCandidates = []) {
|
||||
}
|
||||
|
||||
if (foundPost) {
|
||||
const urlsForPersistence = allUrlsToCheck.filter(urlValue => urlValue && urlValue !== foundPost.url);
|
||||
if (urlsForPersistence.length) {
|
||||
await persistAlternatePostUrls(foundPost.id, urlsForPersistence);
|
||||
}
|
||||
return foundPost;
|
||||
}
|
||||
|
||||
console.log('[FB Tracker] Post not tracked yet (checked', urlsToCheck.length, 'URLs)');
|
||||
console.log('[FB Tracker] Post not tracked yet (checked', allUrlsToCheck.length, 'URLs)');
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error('[FB Tracker] Error checking post status:', error);
|
||||
@@ -615,6 +679,29 @@ async function updatePostUrl(postId, newUrl) {
|
||||
}
|
||||
}
|
||||
|
||||
async function persistAlternatePostUrls(postId, urls = []) {
|
||||
if (!postId || !Array.isArray(urls) || urls.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uniqueUrls = Array.from(new Set(urls.filter(url => typeof url === 'string' && url.trim())));
|
||||
if (!uniqueUrls.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await backendFetch(`${API_URL}/posts/${postId}/urls`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ urls: uniqueUrls })
|
||||
});
|
||||
} catch (error) {
|
||||
console.debug('[FB Tracker] Persisting alternate URLs failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Add post to tracking
|
||||
async function markPostChecked(postId, profileNumber) {
|
||||
try {
|
||||
@@ -663,6 +750,8 @@ async function addPostToTracking(postUrl, targetCount, profileNumber, options =
|
||||
}
|
||||
}
|
||||
|
||||
const alternateCandidates = Array.isArray(options && options.candidates) ? options.candidates : [];
|
||||
|
||||
const normalizedUrl = normalizeFacebookPostUrl(postUrl);
|
||||
if (!normalizedUrl) {
|
||||
console.error('[FB Tracker] Post URL konnte nicht normalisiert werden:', postUrl);
|
||||
@@ -676,6 +765,10 @@ async function addPostToTracking(postUrl, targetCount, profileNumber, options =
|
||||
created_by_profile: profileNumber
|
||||
};
|
||||
|
||||
if (alternateCandidates.length) {
|
||||
payload.alternate_urls = alternateCandidates;
|
||||
}
|
||||
|
||||
if (createdByName) {
|
||||
payload.created_by_name = createdByName;
|
||||
}
|
||||
@@ -697,11 +790,7 @@ async function addPostToTracking(postUrl, targetCount, profileNumber, options =
|
||||
console.log('[FB Tracker] Post added successfully:', data);
|
||||
|
||||
if (data && data.id) {
|
||||
const checkedData = await markPostChecked(data.id, profileNumber);
|
||||
await captureAndUploadScreenshot(data.id, options.postElement || null);
|
||||
if (checkedData) {
|
||||
return checkedData;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -1690,6 +1779,7 @@ function normalizeFacebookPostUrl(rawValue) {
|
||||
const cleanedParams = new URLSearchParams();
|
||||
parsed.searchParams.forEach((paramValue, paramKey) => {
|
||||
const lowerKey = paramKey.toLowerCase();
|
||||
const isSingleUnitParam = lowerKey === 's' && paramValue === 'single_unit';
|
||||
if (
|
||||
lowerKey.startsWith('__cft__')
|
||||
|| lowerKey.startsWith('__tn__')
|
||||
@@ -1698,6 +1788,7 @@ function normalizeFacebookPostUrl(rawValue) {
|
||||
|| lowerKey === 'set'
|
||||
|| lowerKey === 'comment_id'
|
||||
|| lowerKey === 'hoisted_section_header_type'
|
||||
|| isSingleUnitParam
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -1721,6 +1812,127 @@ function normalizeFacebookPostUrl(rawValue) {
|
||||
return formatted.replace(/[?&]$/, '');
|
||||
}
|
||||
|
||||
async function renderTrackedStatus({
|
||||
container,
|
||||
postElement,
|
||||
postData,
|
||||
profileNumber,
|
||||
isFeedHome,
|
||||
isDialogContext,
|
||||
manualHideInfo,
|
||||
encodedUrl,
|
||||
postNum
|
||||
}) {
|
||||
if (!postData) {
|
||||
container.innerHTML = '';
|
||||
return { hidden: false };
|
||||
}
|
||||
|
||||
if (postData.id) {
|
||||
container.dataset.postId = postData.id;
|
||||
}
|
||||
|
||||
const checks = Array.isArray(postData.checks) ? postData.checks : [];
|
||||
const checkedCount = postData.checked_count ?? checks.length;
|
||||
const targetTotal = postData.target_count || checks.length || 0;
|
||||
const statusText = `${checkedCount}/${targetTotal}`;
|
||||
const completed = checkedCount >= targetTotal && targetTotal > 0;
|
||||
const lastCheck = checks.length
|
||||
? new Date(checks[checks.length - 1].checked_at).toLocaleString('de-DE', { timeZone: 'Europe/Berlin' })
|
||||
: null;
|
||||
|
||||
const isExpired = postData.deadline_at ? new Date(postData.deadline_at) < new Date() : false;
|
||||
const canCurrentProfileCheck = postData.next_required_profile === profileNumber;
|
||||
const isCurrentProfileDone = checks.some(check => check.profile_number === profileNumber);
|
||||
|
||||
if (isFeedHome && isCurrentProfileDone) {
|
||||
if (isDialogContext) {
|
||||
console.log('[FB Tracker] Post #' + postNum + ' - Would hide on feed (already checked by current profile) but skipping in dialog context');
|
||||
} else {
|
||||
console.log('[FB Tracker] Post #' + postNum + ' - Hidden on feed (already checked by current profile)');
|
||||
hidePostElement(postElement);
|
||||
processedPostUrls.set(encodedUrl, {
|
||||
element: postElement,
|
||||
createdAt: Date.now(),
|
||||
hidden: true,
|
||||
searchSeenCount: manualHideInfo && typeof manualHideInfo.seen_count === 'number'
|
||||
? manualHideInfo.seen_count
|
||||
: null
|
||||
});
|
||||
return { hidden: true };
|
||||
}
|
||||
}
|
||||
|
||||
const expiredText = isExpired ? ' ⚠️ ABGELAUFEN' : '';
|
||||
|
||||
let statusHtml = `
|
||||
<div style="color: #65676b; white-space: nowrap;">
|
||||
<strong>Tracker:</strong> ${statusText}${completed ? ' ✓' : ''}${expiredText}
|
||||
</div>
|
||||
${lastCheck ? `<div style="color: #65676b; font-size: 12px; white-space: nowrap;">Letzte: ${lastCheck}</div>` : ''}
|
||||
`;
|
||||
|
||||
if (canCurrentProfileCheck && !isExpired && !completed) {
|
||||
statusHtml += `
|
||||
<button class="fb-tracker-check-btn" style="
|
||||
padding: 4px 12px;
|
||||
background-color: #42b72a;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
margin-left: 8px;
|
||||
">
|
||||
✓ Bestätigen
|
||||
</button>
|
||||
`;
|
||||
} else if (isCurrentProfileDone) {
|
||||
statusHtml += `
|
||||
<div style="color: #42b72a; font-size: 12px; white-space: nowrap; margin-left: 8px;">
|
||||
✓ Von dir bestätigt
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
container.innerHTML = statusHtml;
|
||||
|
||||
await addAICommentButton(container, postElement);
|
||||
|
||||
const checkBtn = container.querySelector('.fb-tracker-check-btn');
|
||||
if (checkBtn) {
|
||||
checkBtn.addEventListener('click', async () => {
|
||||
checkBtn.disabled = true;
|
||||
checkBtn.textContent = 'Wird bestätigt...';
|
||||
|
||||
const result = await markPostChecked(postData.id, profileNumber);
|
||||
|
||||
if (result) {
|
||||
await renderTrackedStatus({
|
||||
container,
|
||||
postElement,
|
||||
postData: result,
|
||||
profileNumber,
|
||||
isFeedHome,
|
||||
isDialogContext,
|
||||
manualHideInfo,
|
||||
encodedUrl,
|
||||
postNum
|
||||
});
|
||||
} else {
|
||||
checkBtn.disabled = false;
|
||||
checkBtn.textContent = 'Fehler - Erneut versuchen';
|
||||
checkBtn.style.backgroundColor = '#e74c3c';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[FB Tracker] Showing status:', statusText);
|
||||
return { hidden: false };
|
||||
}
|
||||
|
||||
// Create the tracking UI
|
||||
async function createTrackerUI(postElement, buttonBar, postNum = '?', options = {}) {
|
||||
// Normalize to top-level post container if nested element passed
|
||||
@@ -1789,6 +2001,8 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
|
||||
container.id = 'fb-tracker-ui-post-' + postNum;
|
||||
container.setAttribute('data-post-num', postNum);
|
||||
container.setAttribute('data-post-url', encodedUrl);
|
||||
container.dataset.isFeedHome = isFeedHome ? '1' : '0';
|
||||
container.dataset.isDialogContext = isDialogContext ? '1' : '0';
|
||||
container.style.cssText = `
|
||||
padding: 6px 12px;
|
||||
background-color: #f0f2f5;
|
||||
@@ -1894,111 +2108,21 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
|
||||
}
|
||||
|
||||
if (postData) {
|
||||
const checkedCount = postData.checked_count ?? (Array.isArray(postData.checks) ? postData.checks.length : 0);
|
||||
const statusText = `${checkedCount}/${postData.target_count}`;
|
||||
const completed = checkedCount >= postData.target_count;
|
||||
const lastCheck = Array.isArray(postData.checks) && postData.checks.length
|
||||
? new Date(postData.checks[postData.checks.length - 1].checked_at).toLocaleString('de-DE', { timeZone: 'Europe/Berlin' })
|
||||
: null;
|
||||
const renderResult = await renderTrackedStatus({
|
||||
container,
|
||||
postElement,
|
||||
postData,
|
||||
profileNumber,
|
||||
isFeedHome,
|
||||
isDialogContext,
|
||||
manualHideInfo,
|
||||
encodedUrl,
|
||||
postNum
|
||||
});
|
||||
|
||||
// Check if deadline has passed
|
||||
const isExpired = postData.deadline_at ? new Date(postData.deadline_at) < new Date() : false;
|
||||
const expiredText = isExpired ? ' ⚠️ ABGELAUFEN' : '';
|
||||
|
||||
// Check if current profile can check this post
|
||||
const canCurrentProfileCheck = postData.next_required_profile === profileNumber;
|
||||
const isCurrentProfileDone = Array.isArray(postData.checks) && postData.checks.some(check => check.profile_number === profileNumber);
|
||||
|
||||
if (isFeedHome && isCurrentProfileDone) {
|
||||
if (isDialogContext) {
|
||||
console.log('[FB Tracker] Post #' + postNum + ' - Would hide on feed (already checked by current profile) but skipping in dialog context');
|
||||
} else {
|
||||
console.log('[FB Tracker] Post #' + postNum + ' - Hidden on feed (already checked by current profile)');
|
||||
hidePostElement(postElement);
|
||||
processedPostUrls.set(encodedUrl, {
|
||||
element: postElement,
|
||||
createdAt: Date.now(),
|
||||
hidden: true,
|
||||
searchSeenCount: manualHideInfo && typeof manualHideInfo.seen_count === 'number' ? manualHideInfo.seen_count : null
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (renderResult && renderResult.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
let statusHtml = `
|
||||
<div style="color: #65676b; white-space: nowrap;">
|
||||
<strong>Tracker:</strong> ${statusText}${completed ? ' ✓' : ''}${expiredText}
|
||||
</div>
|
||||
${lastCheck ? `<div style="color: #65676b; font-size: 12px; white-space: nowrap;">Letzte: ${lastCheck}</div>` : ''}
|
||||
`;
|
||||
|
||||
// Add check button if current profile can check and not expired
|
||||
if (canCurrentProfileCheck && !isExpired && !completed) {
|
||||
statusHtml += `
|
||||
<button class="fb-tracker-check-btn" style="
|
||||
padding: 4px 12px;
|
||||
background-color: #42b72a;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
margin-left: 8px;
|
||||
">
|
||||
✓ Bestätigen
|
||||
</button>
|
||||
`;
|
||||
} else if (isCurrentProfileDone) {
|
||||
statusHtml += `
|
||||
<div style="color: #42b72a; font-size: 12px; white-space: nowrap; margin-left: 8px;">
|
||||
✓ Von dir bestätigt
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
container.innerHTML = statusHtml;
|
||||
|
||||
// Add AI button
|
||||
await addAICommentButton(container, postElement);
|
||||
|
||||
// Add event listener for check button
|
||||
const checkBtn = container.querySelector('.fb-tracker-check-btn');
|
||||
if (checkBtn) {
|
||||
checkBtn.addEventListener('click', async () => {
|
||||
checkBtn.disabled = true;
|
||||
checkBtn.textContent = 'Wird bestätigt...';
|
||||
|
||||
const result = await markPostChecked(postData.id, profileNumber);
|
||||
|
||||
if (result) {
|
||||
const newCheckedCount = result.checked_count ?? checkedCount + 1;
|
||||
const newStatusText = `${newCheckedCount}/${postData.target_count}`;
|
||||
const newCompleted = newCheckedCount >= postData.target_count;
|
||||
const newLastCheck = new Date().toLocaleString('de-DE', { timeZone: 'Europe/Berlin' });
|
||||
|
||||
container.innerHTML = `
|
||||
<div style="color: #65676b; white-space: nowrap;">
|
||||
<strong>Tracker:</strong> ${newStatusText}${newCompleted ? ' ✓' : ''}
|
||||
</div>
|
||||
<div style="color: #65676b; font-size: 12px; white-space: nowrap;">Letzte: ${newLastCheck}</div>
|
||||
<div style="color: #42b72a; font-size: 12px; white-space: nowrap; margin-left: 8px;">
|
||||
✓ Von dir bestätigt
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Re-add AI button after update
|
||||
await addAICommentButton(container, postElement);
|
||||
} else {
|
||||
checkBtn.disabled = false;
|
||||
checkBtn.textContent = 'Fehler - Erneut versuchen';
|
||||
checkBtn.style.backgroundColor = '#e74c3c';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[FB Tracker] Showing status:', statusText);
|
||||
} else {
|
||||
// Post not tracked - show add UI
|
||||
const selectId = `tracker-select-${Date.now()}`;
|
||||
@@ -2072,37 +2196,28 @@ async function createTrackerUI(postElement, buttonBar, postNum = '?', options =
|
||||
|
||||
const result = await addPostToTracking(postUrlData.url, targetCount, profileNumber, {
|
||||
postElement,
|
||||
deadline: deadlineValue
|
||||
deadline: deadlineValue,
|
||||
candidates: postUrlData.allCandidates
|
||||
});
|
||||
|
||||
if (result) {
|
||||
const checks = Array.isArray(result.checks) ? result.checks : [];
|
||||
const checkedCount = typeof result.checked_count === 'number' ? result.checked_count : checks.length;
|
||||
const targetTotal = result.target_count || targetCount;
|
||||
const statusText = `${checkedCount}/${targetTotal}`;
|
||||
const completed = checkedCount >= targetTotal;
|
||||
const lastCheck = checks.length ? new Date(checks[checks.length - 1].checked_at).toLocaleString('de-DE', { timeZone: 'Europe/Berlin' }) : null;
|
||||
const renderOutcome = await renderTrackedStatus({
|
||||
container,
|
||||
postElement,
|
||||
postData: result,
|
||||
profileNumber,
|
||||
isFeedHome,
|
||||
isDialogContext,
|
||||
manualHideInfo,
|
||||
encodedUrl,
|
||||
postNum
|
||||
});
|
||||
|
||||
let statusHtml = `
|
||||
<div style="color: #65676b; white-space: nowrap;">
|
||||
<strong>Tracker:</strong> ${statusText}${completed ? ' ✓' : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (lastCheck) {
|
||||
statusHtml += `
|
||||
<div style="color: #65676b; font-size: 12px; white-space: nowrap;">
|
||||
Letzte: ${lastCheck}
|
||||
</div>
|
||||
`;
|
||||
if (renderOutcome && renderOutcome.hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = statusHtml;
|
||||
if (deadlineInput) {
|
||||
deadlineInput.value = '';
|
||||
}
|
||||
|
||||
await addAICommentButton(container, postElement);
|
||||
return;
|
||||
} else {
|
||||
// Error
|
||||
addButton.disabled = false;
|
||||
@@ -3667,6 +3782,77 @@ async function addAICommentButton(container, postElement) {
|
||||
window.removeEventListener('resize', repositionDropdown);
|
||||
};
|
||||
|
||||
const getDecodedPostUrl = () => {
|
||||
const raw = encodedPostUrl || (container && container.getAttribute('data-post-url'));
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return decodeURIComponent(raw);
|
||||
} catch (error) {
|
||||
console.warn('[FB Tracker] Konnte Post-URL nicht dekodieren:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const confirmParticipationAfterAI = async (profileNumber) => {
|
||||
try {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const effectiveProfile = profileNumber || await getProfileNumber();
|
||||
const decodedUrl = getDecodedPostUrl();
|
||||
const isFeedHomeFlag = container.dataset.isFeedHome === '1';
|
||||
const isDialogFlag = container.dataset.isDialogContext === '1';
|
||||
const postNumValue = container.getAttribute('data-post-num') || '?';
|
||||
const encodedUrlValue = container.getAttribute('data-post-url') || '';
|
||||
|
||||
let latestData = null;
|
||||
let postId = container.dataset.postId || '';
|
||||
|
||||
if (postId) {
|
||||
latestData = await markPostChecked(postId, effectiveProfile);
|
||||
if (!latestData && decodedUrl) {
|
||||
const refreshed = await checkPostStatus(decodedUrl);
|
||||
if (refreshed && refreshed.id) {
|
||||
container.dataset.postId = refreshed.id;
|
||||
latestData = await markPostChecked(refreshed.id, effectiveProfile) || refreshed;
|
||||
}
|
||||
}
|
||||
} else if (decodedUrl) {
|
||||
const refreshed = await checkPostStatus(decodedUrl);
|
||||
if (refreshed && refreshed.id) {
|
||||
container.dataset.postId = refreshed.id;
|
||||
latestData = await markPostChecked(refreshed.id, effectiveProfile) || refreshed;
|
||||
}
|
||||
}
|
||||
|
||||
if (!latestData && decodedUrl) {
|
||||
const fallbackStatus = await checkPostStatus(decodedUrl);
|
||||
if (fallbackStatus) {
|
||||
latestData = fallbackStatus;
|
||||
}
|
||||
}
|
||||
|
||||
if (latestData) {
|
||||
await renderTrackedStatus({
|
||||
container,
|
||||
postElement,
|
||||
postData: latestData,
|
||||
profileNumber: effectiveProfile,
|
||||
isFeedHome: isFeedHomeFlag,
|
||||
isDialogContext: isDialogFlag,
|
||||
manualHideInfo: null,
|
||||
encodedUrl: encodedUrlValue,
|
||||
postNum: postNumValue
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[FB Tracker] Auto-confirm nach AI fehlgeschlagen:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOutsideClick = (event) => {
|
||||
if (!wrapper.contains(event.target) && !dropdown.contains(event.target)) {
|
||||
closeDropdown();
|
||||
@@ -4134,6 +4320,7 @@ async function addAICommentButton(container, postElement) {
|
||||
throwIfCancelled();
|
||||
showToast('📋 Kommentarfeld nicht gefunden - In Zwischenablage kopiert', 'info');
|
||||
restoreIdle('📋 Kopiert', 2000);
|
||||
await confirmParticipationAfterAI(profileNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4148,11 +4335,13 @@ async function addAICommentButton(container, postElement) {
|
||||
if (success) {
|
||||
showToast('✓ Kommentar wurde eingefügt', 'success');
|
||||
restoreIdle('✓ Eingefügt', 2000);
|
||||
await confirmParticipationAfterAI(profileNumber);
|
||||
} else {
|
||||
await navigator.clipboard.writeText(comment);
|
||||
throwIfCancelled();
|
||||
showToast('📋 Einfügen fehlgeschlagen - In Zwischenablage kopiert', 'info');
|
||||
restoreIdle('📋 Kopiert', 2000);
|
||||
await confirmParticipationAfterAI(profileNumber);
|
||||
}
|
||||
} catch (error) {
|
||||
const cancelled = aiContext.cancelled || isCancellationError(error);
|
||||
|
||||
Reference in New Issue
Block a user