archive.today webpage capture | Saved from | ||
| All snapshots | from host stories.radiocorax.de | ||
| WebpageScreenshot | |||
let stories = [];
let contacts = [];
// Connect to SSE endpoint
const eventSource = new EventSource('/updates');
// Load stories and contacts when the page is loaded
document.addEventListener('DOMContentLoaded', async () => {
await loadContacts();
loadStories();
});
// Listen for updates from the server
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'UPDATE') {
loadStories(data.stories);
}
};
document.addEventListener('DOMContentLoaded', async function() {
// Wait for contacts to load first
await loadContacts();
// Wait for stories to load before proceeding
await loadStories();
// Now fetch the current user
await fetchCurrentUser();
// Add New Story button
const addStoryButton = document.getElementById('add-story-button');
if (addStoryButton) {
addStoryButton.addEventListener('click', addNewStory);
}
// Reload Entries button
const reloadButton = document.getElementById('reload-button');
if (reloadButton) {
reloadButton.addEventListener('click', loadStories);
}
// Editor filter input
const editorFilterInput = document.getElementById('editor-filter');
const clearEditorFilter = document.getElementById('clear-editor-filter');
if (editorFilterInput) {
// Event listener for autocomplete
editorFilterInput.addEventListener('input', function(event) {
updateEditorFilterAutocomplete(event);
filterStories(); // Ensure filtering is applied when typing
});
// Event listener for showing/hiding the "X" icon
editorFilterInput.addEventListener('input', function() {
clearEditorFilter.style.display = this.value ? 'block' : 'none';
});
if (clearEditorFilter) {
clearEditorFilter.addEventListener('click', function() {
editorFilterInput.value = '';
clearEditorFilter.style.display = 'none';
editorFilterInput.focus();
filterStories(); // Ensure filtering is applied after clearing
});
}
} else {
console.error('Editor filter input not found!');
}
// Filter checkboxes
const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
filterCheckboxes.forEach(checkbox => {
checkbox.addEventListener('change', filterStories); // Apply filters on checkbox change
});
// Dropdown button
const dropdownButton = document.querySelector('.dropdown-button');
if (dropdownButton) {
dropdownButton.addEventListener('click', function() {
const dropdownContent = document.querySelector('.dropdown-content');
dropdownContent.style.display = dropdownContent.style.display === 'block' ? 'none' : 'block';
});
}
const storyDivs = document.querySelectorAll('.storyDiv');
storyDivs.forEach(storyDiv => {
console.log("Attaching background listener to: ", storyDiv); // Check if we are selecting the correct storyDiv
attachBackgroundListeners(storyDiv); // This will attach the background listeners to each story div
});
});
async function fetchCurrentUser() {
try {
const response = await fetch('/api/current-user');
if (response.ok) {
const user = await response.json();
const editorFilterInput = document.getElementById('editor-filter');
const clearEditorFilter = document.getElementById('clear-editor-filter');
if (editorFilterInput) {
// Set the editor filter value from the current user
editorFilterInput.value = user.fullName;
// Show or hide the clear button based on the input value
if (clearEditorFilter) {
clearEditorFilter.style.display = user.fullName ? 'block' : 'none';
}
// Manually trigger the input event to apply the filter immediately
editorFilterInput.dispatchEvent(new Event('input'));
// Manually call filterStories to ensure the stories are filtered
filterStories();
}
} else {
console.error('Failed to fetch current user');
}
} catch (error) {
console.error('Error fetching current user:', error);
}
}
async function loadContacts() {
const response = await fetch('/api/contacts');
if (response.ok) {
contacts = await response.json();
} else {
console.error('Failed to load contacts');
}
}
async function loadStories(storiesData = null) {
let data = storiesData || [];
if (!data.length) {
const response = await fetch('/api/stories');
if (response.ok) {
const result = await response.json();
data = Array.isArray(result) ? result : [];
} else {
console.error('Failed to load stories');
return;
}
}
const container = document.getElementById('stories-container');
container.innerHTML = '';
data.forEach(story => {
const storyDiv = document.createElement('div');
storyDiv.className = story.modified ? 'story modified' : 'story saved';
storyDiv.dataset.id = story.id;
storyDiv.dataset.deleted = story.deleted;
let interviewPartnerInputs = story.interviewPartners.map((partner, index) => `
<div class="interview-partner">
<div class="autocomplete-container">
<input type="text" placeholder="Interview Partner" value="${partner.name}"
data-index="${index}" class="interview-partner-input">
<div class="autocomplete-results" id="autocomplete-results-${index}"></div>
</div>
<input type="text" placeholder="Organization" value="${partner.organization || ''}" class="partner-org-input" data-index="${index}">
<input type="text" placeholder="Telephone" value="${partner.telephone || ''}" class="partner-tel-input" data-index="${index}">
<input type="text" placeholder="Second Telephone" value="${partner.secondTelephone || ''}" class="partner-second-tel-input" data-index="${index}">
<input type="text" placeholder="Email" value="${partner.email || ''}" class="partner-email-input" data-index="${index}">
</div>
`).join('');
let helpIcon = '';
if (story.helpNeeded && (story.helpNeeded.feedback || story.helpNeeded.voiceRecordings)) {
let backgroundStyle;
if (story.helpNeeded.voiceRecordings && story.helpNeeded.feedback) {
backgroundStyle = 'linear-gradient(135deg, orange 50%, red 50%)';
} else if (story.helpNeeded.voiceRecordings) {
backgroundStyle = '#dc3545';
} else if (story.helpNeeded.feedback) {
backgroundStyle = 'orange';
}
helpIcon = `
<i class="material-icons help-icon"
style="
color: white;
background: ${backgroundStyle};
padding: 4px 4px;
border-radius: 0px;
display: inline-block;">
error_outline
</i>`;
}
// Check if the story is LIVE
let liveStatusHTML = '';
if (story.isLive) {
liveStatusHTML = `
<div class="status-selection">
<label>
<input type="radio" name="story-status-${story.id}" value="planned" class="status-radio" data-story-id="${story.id}">
Planned
</label>
<label>
<input type="radio" name="story-status-${story.id}" value="live" checked class="status-radio" data-story-id="${story.id}">
LIVE
</label>
<div id="live-options-${story.id}" style="display: block;">
<label>
Date: <input type="date" class="live-date-input" data-story-id="${story.id}" value="${story.liveDate}">
</label>
<label>
<select class="live-channel-select" data-story-id="${story.id}">
<option value="MoMa" ${story.liveChannel === 'MoMa' ? 'selected' : ''}>MoMa</option>
<option value="WiHa" ${story.liveChannel === 'WiHa' ? 'selected' : ''}>WiHa</option>
</select>
</label>
</div>
</div>
`;
} else {
liveStatusHTML = `
<div class="status-selection">
<label>
<input type="radio" name="story-status-${story.id}" value="planned" checked class="status-radio" data-story-id="${story.id}">
Planned
</label>
<label>
<input type="radio" name="story-status-${story.id}" value="live" class="status-radio" data-story-id="${story.id}">
LIVE
</label>
<div id="live-options-${story.id}" style="display: none;">
<label>
Date: <input type="date" class="live-date-input" data-story-id="${story.id}" value="${new Date().toISOString().split('T')[0]}">
</label>
<label>
<select class="live-channel-select" data-story-id="${story.id}">
<option value="MoMa">MoMa</option>
<option value="WiHa">WiHa</option>
</select>
</label>
</div>
</div>
`;
}
storyDiv.innerHTML = `
<div class="story-top" style="display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center;">
<div class="support-request-container" style="display: flex; align-items: center;">
${helpIcon}
<span style="margin-left: 8px;">Support Request?</span>
</div>
<label style="margin-left: 20px;">
<input type="checkbox" class="feedback-checkbox" data-story-id="${story.id}" ${story.helpNeeded && story.helpNeeded.feedback ? 'checked' : ''}>
Feedback
</label>
<label style="margin-left: 20px;">
<input type="checkbox" class="voice-recordings-checkbox" data-story-id="${story.id}" ${story.helpNeeded && story.helpNeeded.voiceRecordings ? 'checked' : ''}>
Voice Recordings
</label>
</div>
<div class="sbutton-container" style="display: flex; align-items: center;">
<span class="last-edited" style="margin-right: 10px;">Last edited: ${new Date(story.lastEdited).toLocaleString()}</span>
<button class="save-button" data-story-id="${story.id}" style="margin-left: 5px;">Save</button>
<button class="delete-button" data-story-id="${story.id}" style="margin-left: 5px;">Delete</button>
</div>
</div>
<div class="story-inputs">
<input type="text" placeholder="Story Title" class="story-title-input" data-story-id="${story.id}" value="${story.title}">
<div class="autocomplete-container">
<input type="text" placeholder="Responsible Editor" class="editor-input" data-story-id="${story.id}" value="${story.editor}">
<div class="autocomplete-results" id="autocomplete-results-editor-${story.id}"></div>
</div>
<input type="text" placeholder="Story Format" class="story-format-input" data-story-id="${story.id}" value="${story.format}">
<input type="number" placeholder="Length in Minutes" class="story-length-input" data-story-id="${story.id}" value="${story.length}">
</div>
<div class="status">
${liveStatusHTML}
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="1" ${story.status[1] ? 'checked' : ''}> Recorded</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="2" ${story.status[2] ? 'checked' : ''}> Produced</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="3" ${story.status[3] ? 'checked' : ''}> Aired (MoMa)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="4" ${story.status[4] ? 'checked' : ''}> Aired (WiHa)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="5" ${story.status[5] ? 'checked' : ''}> Published (FRN)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="6" ${story.status[6] ? 'checked' : ''}> Cross-Media-Published (Corax-Webseite)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${story.id}" data-status-index="7" ${story.status[7] ? 'checked' : ''}> Link sent to Interviewees</label>
</div>
<div>
<details>
<summary>Story Details</summary>
<div class="interview-partners">
${interviewPartnerInputs}
<button class="add-interview-partner-button" data-story-id="${story.id}">+</button>
</div>
<details>
<summary>Moderation</summary>
<textarea placeholder="Enter moderation text here..." class="moderation-textarea" data-story-id="${story.id}">${story.moderation}</textarea>
</details>
<details>
<summary>Teasertext</summary>
<textarea placeholder="Enter teaser text here..." class="teasertext-textarea" data-story-id="${story.id}">${story.teasertext}</textarea>
</details>
<details>
<summary>FRN Link</summary>
<textarea placeholder="Enter FRN link here..." class="frn-link-textarea" data-story-id="${story.id}">${story.frnLink}</textarea>
</details>
</details>
</div>
`;
container.appendChild(storyDiv);
});
// Add event listeners to dynamically created elements
addDynamicEventListeners();
updateStoryOrder();
// Call filterStories after stories are loaded and rendered
filterStories();
}
async function addNewStory() {
const container = document.getElementById('stories-container');
const storyDiv = document.createElement('div');
storyDiv.className = 'story modified';
const uniqueId = uuidv4();
storyDiv.dataset.id = uniqueId;
// Radio buttons for selecting "Planned" or "LIVE"
const statusSelectionHTML = `
<div class="status-selection">
<label>
<input type="radio" name="story-status-${uniqueId}" value="planned" checked class="status-radio" data-story-id="${uniqueId}">
Planned
</label>
<label>
<input type="radio" name="story-status-${uniqueId}" value="live" class="status-radio" data-story-id="${uniqueId}">
LIVE
</label>
<div id="live-options-${uniqueId}" style="display: none;">
<label>
Date: <input type="date" class="live-date-input" data-story-id="${uniqueId}" value="${new Date().toISOString().split('T')[0]}">
</label>
<label>
<select class="live-channel-select" data-story-id="${uniqueId}">
<option value="MoMa">MoMa</option>
<option value="WiHa">WiHa</option>
</select>
</label>
</div>
</div>
`;
storyDiv.innerHTML = `
<div class="story-top">
<div>
<span style="position:absolute; left:60px">Support Request?</span>
<label style="position:absolute; left:200px">
<input type="checkbox" class="feedback-checkbox" data-story-id="${uniqueId}">
Feedback
</label>
<label style="position:absolute; left:300px">
<input type="checkbox" class="voice-recordings-checkbox" data-story-id="${uniqueId}">
Voice Recordings
</label>
</div>
<div class="sbutton-container">
<span class="last-edited">Last edited: Just now</span>
<span class="button-separator"></span>
<button class="save-button" data-story-id="${uniqueId}" style="margin-left: 5px;">Save</button>
<span class="button-separator"></span>
<button class="delete-button" data-story-id="${uniqueId}" style="margin-left: 5px;">Delete</button>
</div>
</div>
<div class="story-inputs">
<input type="text" placeholder="Story Title" class="story-title-input" data-story-id="${uniqueId}">
<div class="autocomplete-container">
<input type="text" placeholder="Responsible Editor" class="editor-input" data-story-id="${uniqueId}">
<div class="autocomplete-results" id="autocomplete-results-editor-${uniqueId}"></div>
</div>
<input type="text" placeholder="Story Format" class="story-format-input" data-story-id="${uniqueId}">
<input type="number" placeholder="Length in Minutes" class="story-length-input" data-story-id="${uniqueId}">
</div>
<div class="status">
${statusSelectionHTML}
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="1"> Recorded</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="2"> Produced</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="3"> Aired (MoMa)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="4"> Aired (WiHa)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="5"> Published (FRN)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="6"> Cross-Media-Published (Corax-Webseite)</label>
<label><input type="checkbox" class="status-checkbox" data-story-id="${uniqueId}" data-status-index="7"> Link sent to Interviewees</label>
</div>
<details>
<summary>Story Details</summary>
<div class="interview-partners">
<div class="interview-partner">
<div class="autocomplete-container">
<input type="text" placeholder="Interview Partner" class="interview-partner-input" data-index="0" data-story-id="${uniqueId}">
<div class="autocomplete-results" id="autocomplete-results-0"></div>
</div>
<input type="text" placeholder="Organization" class="partner-org-input" data-index="0" data-story-id="${uniqueId}">
<input type="text" placeholder="Telephone" class="partner-tel-input" data-index="0" data-story-id="${uniqueId}">
<input type="text" placeholder="Second Telephone" class="partner-second-tel-input" data-index="0" data-story-id="${uniqueId}">
<input type="text" placeholder="Email" class="partner-email-input" data-index="0" data-story-id="${uniqueId}">
</div>
<button class="add-interview-partner-button" data-story-id="${uniqueId}">+</button>
<details>
<summary>Moderation</summary>
<textarea placeholder="Enter moderation text here..." class="moderation-textarea" data-story-id="${uniqueId}"></textarea>
</details>
<details>
<summary>Teasertext</summary>
<textarea placeholder="Enter teaser text here..." class="teasertext-textarea" data-story-id="${uniqueId}"></textarea>
</details>
<details>
<summary>FRN Link</summary>
<textarea placeholder="Enter FRN link here..." class="frn-link-textarea" data-story-id="${uniqueId}"></textarea>
</details>
</div>
</details>
`;
container.insertBefore(storyDiv, container.firstChild);
addDynamicEventListeners();
}
function handleStatusSelection(event) {
const radio = event.target;
const uniqueId = radio.dataset.storyId;
const liveOptionsDiv = document.getElementById(`live-options-${uniqueId}`);
if (radio.value === 'planned') {
liveOptionsDiv.style.display = 'none';
} else if (radio.value === 'live') {
liveOptionsDiv.style.display = 'block';
}
markStoryAsModified(radio);
}
function addInterviewPartner(event) {
const button = event.target;
const storyId = button.dataset.storyId;
const partnerIndex = document.querySelectorAll(`.interview-partner[data-story-id="${storyId}"]`).length;
const partnerDiv = document.createElement('div');
partnerDiv.className = 'interview-partner';
partnerDiv.dataset.storyId = storyId;
partnerDiv.innerHTML = `
<div class="autocomplete-container">
<input type="text" placeholder="Interview Partner" class="interview-partner-input" data-index="${partnerIndex}" data-story-id="${storyId}">
<div class="autocomplete-results" id="autocomplete-results-${partnerIndex}"></div>
</div>
<input type="text" placeholder="Organization" class="partner-org-input" data-index="${partnerIndex}" data-story-id="${storyId}">
<input type="text" placeholder="Telephone" class="partner-tel-input" data-index="${partnerIndex}" data-story-id="${storyId}">
<input type="text" placeholder="Second Telephone" class="partner-second-tel-input" data-index="${partnerIndex}" data-story-id="${storyId}">
<input type="text" placeholder="Email" class="partner-email-input" data-index="${partnerIndex}" data-story-id="${storyId}">
`;
button.parentNode.insertBefore(partnerDiv, button);
addDynamicEventListeners();
}
function markStoryAsModified(element) {
const storyDiv = element.closest('.story');
storyDiv.classList.add('modified');
storyDiv.classList.remove('saved');
updateStoryBackground(storyDiv);
}
async function saveStory(event) {
const button = event.target;
const storyDiv = button.closest('.story');
const storyId = button.dataset.storyId;
const checkboxes = storyDiv.querySelectorAll('.status-checkbox');
const feedbackCheckbox = storyDiv.querySelector('.feedback-checkbox');
const voiceRecordingsCheckbox = storyDiv.querySelector('.voice-recordings-checkbox');
const interviewPartnerDivs = storyDiv.querySelectorAll('.interview-partner');
const isLive = storyDiv.querySelector(`input[name="story-status-${storyId}"]:checked`).value === 'live';
let liveDate = '';
let liveChannel = '';
if (isLive) {
liveDate = storyDiv.querySelector('.live-date-input').value;
liveChannel = storyDiv.querySelector('.live-channel-select').value;
}
const interviewPartners = Array.from(interviewPartnerDivs).map(div => {
const inputs = div.querySelectorAll('input[type="text"]');
return {
name: inputs[0].value,
organization: inputs[1].value,
telephone: inputs[2].value,
secondTelephone: inputs[3].value,
email: inputs[4].value
};
});
const status = [false]; // Initialize story.status[0] to false
checkboxes.forEach(checkbox => {
status[parseInt(checkbox.dataset.statusIndex)] = checkbox.checked;
});
const storyData = {
id: storyId,
title: storyDiv.querySelector('.story-title-input').value,
editor: storyDiv.querySelector('.editor-input').value,
format: storyDiv.querySelector('.story-format-input').value,
length: storyDiv.querySelector('.story-length-input').value,
interviewPartners: interviewPartners,
moderation: storyDiv.querySelector('.moderation-textarea').value,
teasertext: storyDiv.querySelector('.teasertext-textarea').value,
frnLink: storyDiv.querySelector('.frn-link-textarea').value,
status: status,
helpNeeded: {
feedback: feedbackCheckbox ? feedbackCheckbox.checked : false,
voiceRecordings: voiceRecordingsCheckbox ? voiceRecordingsCheckbox.checked : false
},
isLive: isLive,
liveDate: liveDate,
liveChannel: liveChannel,
lastEdited: new Date().toISOString()
};
try {
const response = await fetch('/api/stories', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(storyData),
});
if (response.ok) {
console.log('Story updated successfully');
storyDiv.querySelector('.last-edited').textContent = `Last edited: ${new Date(storyData.lastEdited).toLocaleString()}`;
storyDiv.classList.remove('modified');
storyDiv.classList.add('saved');
updateStoryOrder();
// Store current filter settings
const filterCheckboxes = Array.from(document.querySelectorAll('.dropdown-content input[type="checkbox"]'));
const editorFilterValue = document.getElementById('editor-filter').value;
const supportNeededFilterValue = document.getElementById('support-needed-filter').checked;
// Reload stories to ensure the UI reflects the current saved state
await loadStories();
// Reapply filter settings
document.getElementById('editor-filter').value = editorFilterValue;
document.getElementById('support-needed-filter').checked = supportNeededFilterValue;
filterCheckboxes.forEach((checkbox, index) => {
checkbox.checked = checkbox.checked;
});
// Reapply the filter
filterStories();
} else {
console.error('Failed to update story');
}
} catch (error) {
console.error('Error updating story:', error);
}
}
async function deleteStory(event) {
const button = event.target;
const storyId = button.dataset.storyId;
// Save current filter settings
const editorFilterValue = document.getElementById('editor-filter').value;
const supportNeededFilterValue = document.getElementById('support-needed-filter').checked;
const filterCheckboxes = Array.from(document.querySelectorAll('.dropdown-content input[type="checkbox"]'));
try {
const response = await fetch('/api/stories', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ id: storyId }),
});
if (response.ok) {
console.log('Story marked as deleted successfully');
// Reload stories to update the UI
await loadStories();
// Reapply filter settings
document.getElementById('editor-filter').value = editorFilterValue;
document.getElementById('support-needed-filter').checked = supportNeededFilterValue;
filterCheckboxes.forEach((checkbox, index) => {
const savedCheckbox = document.querySelector(`.dropdown-content input[type="checkbox"][data-filter="${checkbox.dataset.filter}"]`);
if (savedCheckbox) {
savedCheckbox.checked = checkbox.checked;
}
});
// Reapply the filter
filterStories();
} else {
console.error('Failed to mark story as deleted');
}
} catch (error) {
console.error('Error marking story as deleted:', error);
}
}
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function updateStoryOrder() {
const container = document.getElementById('stories-container');
const stories = Array.from(container.getElementsByClassName('story'));
stories.sort((a, b) => {
const aChecked = a.querySelectorAll('.status-checkbox:checked').length;
const bChecked = b.querySelectorAll('.status-checkbox:checked').length;
return aChecked - bChecked;
});
container.innerHTML = '';
stories.forEach(story => container.appendChild(story));
}
function updateStoryBackground(storyDiv) {
if (storyDiv.classList.contains('modified')) {
storyDiv.style.background = '#ffe59d';
return;
}
const checkboxes = storyDiv.querySelectorAll('.status-checkbox');
const total = checkboxes.length;
const checkedCount = Array.from(checkboxes).filter(cb => cb.checked).length;
const fillPercent = (checkedCount / total) * 100;
const transitionWidth = 15;
const fadeEnd = Math.min(fillPercent + transitionWidth, 100);
storyDiv.style.background = `
linear-gradient(to right,
#6C9AC4 0%,
#81A9CE ${fillPercent}%,
#ACC8E1 ${fadeEnd}%,
#c1d7eb 100%)
`;
}
function attachBackgroundListeners(storyDiv) {
const checkboxes = storyDiv.querySelectorAll('.status-checkbox');
checkboxes.forEach(cb => {
cb.addEventListener('change', () => {
updateStoryBackground(storyDiv);
});
});
}
function attachBackgroundListeners(storyDiv) {
console.log("Inside attachBackgroundListeners for:", storyDiv);
const checkboxes = storyDiv.querySelectorAll('.status-checkbox');
if (checkboxes.length === 0) {
console.log("No checkboxes found inside storyDiv:", storyDiv);
return;
}
checkboxes.forEach(cb => {
console.log("Attaching listener to checkbox:", cb);
cb.addEventListener('change', () => {
console.log("Checkbox state changed for checkbox:", cb);
updateStoryBackground(storyDiv); // This will update the background
});
});
}
function autocomplete(input, inputIndex) {
const inputValue = input.value.toLowerCase();
return contacts.filter(contact =>
contact.name.toLowerCase().includes(inputValue)
);
}
function updateAutocomplete(event) {
const input = event.target;
const inputIndex = input.dataset.index;
const storyId = input.dataset.storyId;
const resultsContainer = document.getElementById(`autocomplete-results-${inputIndex}`);
resultsContainer.style.top = `${input.offsetHeight}px`;
resultsContainer.style.left = `0`;
const suggestions = autocomplete(input, inputIndex);
resultsContainer.innerHTML = '';
suggestions.forEach((contact, index) => {
const div = document.createElement('div');
div.textContent = contact.name;
div.dataset.index = index;
div.addEventListener('click', function() {
input.value = contact.name;
const inputs = input.closest('.interview-partner').querySelectorAll('input[type="text"]');
inputs[1].value = contact.organization || '';
inputs[2].value = contact.telephone || '';
inputs[3].value = contact.secondTelephone || '';
inputs[4].value = contact.email || '';
markStoryAsModified(input);
resultsContainer.innerHTML = '';
resultsContainer.style.display = 'none';
});
resultsContainer.appendChild(div);
});
if (suggestions.length > 0) {
resultsContainer.style.display = 'block';
// Add keyboard navigation
let selectedIndex = -1;
input.addEventListener('keydown', function(event) {
const divs = resultsContainer.querySelectorAll('div');
if (event.key === 'ArrowDown') {
event.preventDefault();
selectedIndex = (selectedIndex + 1) % divs.length;
divs.forEach((div, i) => {
div.style.backgroundColor = i === selectedIndex ? '#ddd' : '';
});
} else if (event.key === 'ArrowUp') {
event.preventDefault();
selectedIndex = (selectedIndex - 1 + divs.length) % divs.length;
divs.forEach((div, i) => {
div.style.backgroundColor = i === selectedIndex ? '#ddd' : '';
});
} else if (event.key === 'Enter' && selectedIndex >= 0) {
event.preventDefault();
input.value = suggestions[selectedIndex].name;
const inputs = input.closest('.interview-partner').querySelectorAll('input[type="text"]');
inputs[1].value = suggestions[selectedIndex].organization || '';
inputs[2].value = suggestions[selectedIndex].telephone || '';
inputs[3].value = suggestions[selectedIndex].secondTelephone || '';
inputs[4].value = suggestions[selectedIndex].email || '';
markStoryAsModified(input);
resultsContainer.innerHTML = '';
resultsContainer.style.display = 'none';
}
});
} else {
resultsContainer.style.display = 'none';
}
}
function updateEditorAutocomplete(event) {
const input = event.target;
const storyId = input.dataset.storyId;
const resultsContainer = document.getElementById(`autocomplete-results-editor-${storyId}`);
const inputValue = input.value.toLowerCase();
const suggestions = contacts.filter(contact =>
contact.name.toLowerCase().includes(inputValue)
);
resultsContainer.innerHTML = '';
suggestions.forEach((contact, index) => {
const div = document.createElement('div');
div.textContent = contact.name;
div.dataset.index = index;
div.addEventListener('click', function() {
input.value = contact.name;
markStoryAsModified(input);
resultsContainer.innerHTML = '';
resultsContainer.style.display = 'none';
});
resultsContainer.appendChild(div);
});
if (suggestions.length > 0) {
resultsContainer.style.display = 'block';
resultsContainer.style.top = `${input.offsetHeight + input.offsetTop}px`;
resultsContainer.style.left = `${input.offsetLeft}px`;
resultsContainer.style.position = 'absolute';
// Add keyboard navigation
let selectedIndex = -1;
input.addEventListener('keydown', function(event) {
const divs = resultsContainer.querySelectorAll('div');
if (event.key === 'ArrowDown') {
event.preventDefault();
selectedIndex = (selectedIndex + 1) % divs.length;
divs.forEach((div, i) => {
div.style.backgroundColor = i === selectedIndex ? '#ddd' : '';
});
} else if (event.key === 'ArrowUp') {
event.preventDefault();
selectedIndex = (selectedIndex - 1 + divs.length) % divs.length;
divs.forEach((div, i) => {
div.style.backgroundColor = i === selectedIndex ? '#ddd' : '';
});
} else if (event.key === 'Enter' && selectedIndex >= 0) {
event.preventDefault();
input.value = suggestions[selectedIndex].name;
markStoryAsModified(input);
resultsContainer.innerHTML = '';
resultsContainer.style.display = 'none';
}
});
} else {
resultsContainer.style.display = 'none';
}
}
function updateEditorFilterAutocomplete(event) {
const input = event.target;
const resultsContainer = document.getElementById('autocomplete-results-editor-filter');
const inputValue = input.value.toLowerCase();
const suggestions = contacts.filter(contact =>
contact.name.toLowerCase().includes(inputValue)
);
resultsContainer.innerHTML = ''; // Clear previous results
// Create and display suggestions
suggestions.forEach((contact, index) => {
const div = document.createElement('div');
div.textContent = contact.name;
div.dataset.index = index;
// Add click handler to fill input with selected contact
div.addEventListener('click', function() {
input.value = contact.name;
resultsContainer.innerHTML = ''; // Clear suggestions
resultsContainer.style.display = 'none'; // Hide suggestions
});
resultsContainer.appendChild(div);
});
// Show or hide the results container based on suggestions
if (suggestions.length > 0) {
resultsContainer.style.display = 'block';
} else {
resultsContainer.style.display = 'none';
}
// Add keyboard navigation only if there are results
if (suggestions.length > 0) {
let selectedIndex = -1;
// Add a keydown listener for keyboard navigation
input.addEventListener('keydown', function(event) {
const divs = resultsContainer.querySelectorAll('div');
if (event.key === 'ArrowDown') {
event.preventDefault();
selectedIndex = (selectedIndex + 1) % divs.length;
updateSelectedItem(divs, selectedIndex);
} else if (event.key === 'ArrowUp') {
event.preventDefault();
selectedIndex = (selectedIndex - 1 + divs.length) % divs.length;
updateSelectedItem(divs, selectedIndex);
} else if (event.key === 'Enter' && selectedIndex >= 0) {
event.preventDefault();
input.value = suggestions[selectedIndex].name;
resultsContainer.innerHTML = ''; // Clear suggestions
resultsContainer.style.display = 'none'; // Hide suggestions
}
});
}
}
// Helper function to update the selected item's background
function updateSelectedItem(divs, selectedIndex) {
divs.forEach((div, i) => {
div.style.backgroundColor = i === selectedIndex ? '#ddd' : '';
});
}
function filterStories() {
const filterCheckboxes = Array.from(document.querySelectorAll('.dropdown-content input[type="checkbox"]')).slice(0, -1);
const editorFilter = document.getElementById('editor-filter').value.toLowerCase();
const supportNeededFilter = document.getElementById('support-needed-filter').checked;
const stories = document.querySelectorAll('.story');
stories.forEach(story => {
// Check if the story is deleted and immediately hide it if true
if (story.dataset.deleted === 'true') {
story.style.display = 'none';
return; // Skip to the next story
}
const storyCheckboxes = story.querySelectorAll('.status-checkbox');
const editorName = story.querySelector('.editor-input').value.toLowerCase();
const feedbackCheckbox = story.querySelector('.feedback-checkbox');
const voiceRecordingsCheckbox = story.querySelector('.voice-recordings-checkbox');
const isLive = story.querySelector('input[name^="story-status"]:checked').value === 'live';
const isPlanned = story.querySelector('input[name^="story-status"]:checked').value === 'planned';
const editorMatch = editorName.includes(editorFilter);
const supportNeededMatch = !supportNeededFilter || (feedbackCheckbox?.checked || voiceRecordingsCheckbox?.checked);
let shouldDisplay = false;
const anyFilterChecked = filterCheckboxes.some(checkbox => checkbox.checked);
if (!anyFilterChecked && editorFilter === '' && !supportNeededFilter) {
shouldDisplay = true;
} else {
const plannedFilterChecked = filterCheckboxes[0].checked;
const liveFilterChecked = filterCheckboxes[1].checked;
// Check if all selected filters match the story's status
const statusMatch = filterCheckboxes.every((filterCheckbox, index) => {
if (!filterCheckbox.checked) {
return true; // Skip unchecked filters
}
if (index === 0) {
return isPlanned;
}
if (index === 1) {
return isLive;
}
return storyCheckboxes[index - 2]?.checked;
});
shouldDisplay = statusMatch && editorMatch && supportNeededMatch;
}
// Apply the final display logic
story.style.display = shouldDisplay ? 'block' : 'none';
});
}
function addDynamicEventListeners() {
// Add event listeners to dynamically created elements
document.querySelectorAll('.save-button').forEach(button => {
button.addEventListener('click', saveStory);
});
document.querySelectorAll('.delete-button').forEach(button => {
button.addEventListener('click', deleteStory);
});
document.querySelectorAll('.status-radio').forEach(radio => {
radio.addEventListener('change', handleStatusSelection);
});
document.querySelectorAll('.add-interview-partner-button').forEach(button => {
button.addEventListener('click', addInterviewPartner);
});
document.querySelectorAll('.interview-partner-input').forEach(input => {
input.addEventListener('input', updateAutocomplete);
});
document.querySelectorAll('.editor-input').forEach(input => {
input.addEventListener('input', updateEditorAutocomplete);
});
document.querySelectorAll('.story-title-input, .story-format-input, .story-length-input, .moderation-textarea, .teasertext-textarea, .frn-link-textarea, .partner-org-input, .partner-tel-input, .partner-second-tel-input, .partner-email-input').forEach(input => {
input.addEventListener('change', function() {
markStoryAsModified(this);
});
});
document.querySelectorAll('.feedback-checkbox, .voice-recordings-checkbox, .status-checkbox').forEach(checkbox => {
checkbox.addEventListener('change', function() {
markStoryAsModified(this);
});
});
}
// Close dropdowns when clicking outside
document.addEventListener('click', function(event) {
const dropdownContents = document.querySelectorAll('.dropdown-content, .autocomplete-results');
dropdownContents.forEach(dropdown => {
if (!dropdown.contains(event.target) &&
!event.target.classList.contains('dropdown-button') &&
!event.target.closest('.autocomplete-container') &&
!event.target.closest('.dropdown-button')) {
dropdown.style.display = 'none';
}
});
});
// Close dropdowns and clear input when ESC key is pressed
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
// Close the dropdowns
const dropdownContents = document.querySelectorAll('.dropdown-content, .autocomplete-results');
dropdownContents.forEach(dropdown => {
dropdown.style.display = 'none';
});
// Clear the input field if it's an editor filter input
const editorFilterInput = document.getElementById('editor-filter');
if (editorFilterInput) {
editorFilterInput.value = ''; // Clear the text input
}
}
});