Family Oral History Interview Prompt Customizer

Family Oral History Interview Prompt Customizer

Interview Subject

Select Core Topics

Check the categories you wish to cover during the interview. This will populate the next tab.

Review, **edit**, and select the specific questions you want to use for the interview.

This is your final script. Use the arrows to reorder questions for a better conversational flow.

Your final interview guide is ready for export.

Click "Next" or "Previous" to refresh this preview.

No questions were selected for the interview.

'; } else { html += '
    '; reviewItems.forEach(li => { const category = li.dataset.category; const promptText = li.querySelector('p').textContent.replace(` (${category})`, ''); if (category && category !== currentCategory) { if (currentCategory !== '') html += '
'; html += `

${escapeHTML(category)}

    `; currentCategory = category; } html += `
  1. ${promptText}
  2. `; count++; }); html += '
'; } summaryPreview.innerHTML = html; }; const getRecipeData = () => { const finalPrompts = getFinalPrompts(); // Use the VISUALLY ORDERED list from Tab 3 for TXT/PDF export const orderedPrompts = Array.from(reviewList.children).map(li => ({ category: li.dataset.category, text: li.querySelector('p').textContent.replace(` (${li.dataset.category})`, '') })); return { subjectName: subjectNameInput.value || 'Interview Subject', interviewerName: interviewerNameInput.value || 'Interviewer', prompts: orderedPrompts.length > 0 ? orderedPrompts : finalPrompts, // Fallback date: new Date().toLocaleDateString() }; }; const downloadTxt = () => { const data = getRecipeData(); let content = `ORAL HISTORY INTERVIEW GUIDE\n`; content += "========================================\n"; content += `Subject: ${data.subjectName}\n`; content += `Interviewer: ${data.interviewerName}\n`; content += `Date: ${data.date}\n`; content += "========================================\n\n"; let currentCategory = ''; let count = 1; data.prompts.forEach(prompt => { if (prompt.category !== currentCategory) { content += `\n--- ${prompt.category.toUpperCase()} ---\n`; currentCategory = prompt.category; count = 1; } content += `${count}. ${prompt.text}\n`; count++; }); const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `interview_guide_${data.subjectName.replace(/ /g, '_')}.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(a.href); }; const downloadPDF = () => { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library not loaded.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'mm', 'a4'); const data = getRecipeData(); const margin = 20; const pageWidth = doc.internal.pageSize.getWidth(); const usableWidth = pageWidth - margin * 2; let yPos = 25; // --- Helper for wrapping text and list item generation const addWrappedText = (text, size, style, color = [52, 73, 94], lineSpacing = 6) => { doc.setFontSize(size); doc.setFont(undefined, style); doc.setTextColor(color[0], color[1], color[2]); const splitText = doc.splitTextToSize(text, usableWidth); if (yPos + (splitText.length * lineSpacing) > 280) { doc.addPage(); yPos = 20; } doc.text(splitText, margin, yPos); yPos += (splitText.length * lineSpacing); }; const addListItem = (text, number) => { const prefix = `${number}. `; doc.setFontSize(11); doc.setFont(undefined, 'normal'); doc.setTextColor(52, 73, 94); const splitText = doc.splitTextToSize(text, usableWidth - 10); // indent for number if (yPos + (splitText.length * 6) > 280) { doc.addPage(); yPos = 20; } doc.text(prefix, margin, yPos); doc.text(splitText, margin + 5, yPos); yPos += (splitText.length * 6); }; // --- Build PDF Document --- // 1. Title & Metadata doc.setFontSize(18); doc.setFont(undefined, 'bold'); doc.setTextColor(44, 62, 80); doc.text(`Oral History Interview Guide`, pageWidth / 2, yPos, { align: 'center' }); yPos += 8; doc.setFontSize(10); doc.setTextColor(108, 117, 125); doc.text(`Subject: ${data.subjectName} | Interviewer: ${data.interviewerName} | Date: ${data.date}`, pageWidth / 2, yPos, { align: 'center' }); yPos += 15; // 2. Questions by Category let currentCategory = ''; let count = 1; data.prompts.forEach((prompt, index) => { if (prompt.category !== currentCategory) { yPos += 5; // Category Header doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(230, 126, 34); // Orange doc.text(prompt.category.toUpperCase(), margin, yPos); doc.setDrawColor(224, 224, 224); doc.line(margin, yPos + 1, pageWidth - margin, yPos + 1); yPos += 8; currentCategory = prompt.category; } addListItem(prompt.text, index + 1); }); doc.save(`interview_guide_${data.subjectName.replace(/ /g, '_')}.pdf`); }; // --- Event Listeners --- // Global Navigation nextBtn.addEventListener('click', () => showTab(currentTab + 1)); prevBtn.addEventListener('click', () => showTab(currentTab - 1)); // Tab 1 Actions topicSelectionArea.addEventListener('change', (e) => { if (e.target.type === 'checkbox') { handleTopicSelection(e.target.dataset.id, e.target.checked); } }); // Tab 2 Actions promptCustomizerArea.addEventListener('change', (e) => { const target = e.target; if (target.type === 'checkbox') { updatePrompt(target.dataset.topicId, target.dataset.qId, 'selected', target.checked); } }); promptCustomizerArea.addEventListener('blur', (e) => { const target = e.target; if (target.type === 'text') { updatePrompt(target.dataset.topicId, target.dataset.qId, 'text', target.value); } }, true); // Tab 3 Actions refreshReviewBtn.addEventListener('click', renderReviewList); // Tab 4 Actions downloadPdfBtn.addEventListener('click', downloadPDF); downloadTxtBtn.addEventListener('click', downloadTxt); // --- Initialization --- showTab(1); // Set initial state });
Scroll to Top