/** * TPU Survey - Standalone Editor Logic * รองรับ Section -> Heading -> Question */ let currentSurvey = null; let isDirty = false; async function initEditor() { const urlParams = new URLSearchParams(window.location.search); const id = urlParams.get('id'); if (!id) { alert('ไม่ระบุ ID แบบสอบถาม'); window.close(); return; } try { const data = await API.get(`surveys.php?action=get&id=${id}`); currentSurvey = data.survey; renderEditor(); } catch (err) { Toast.error(err.message); document.getElementById('editorContent').innerHTML = `
❌

เกิดข้อผิดพลาด

${err.message}

`; } } function renderEditor() { if (!currentSurvey) return; document.title = `แก้ไข: ${currentSurvey.title} - TPU Survey`; document.getElementById('surveyTitleDisplay').textContent = currentSurvey.title; let html = `

⚙️ ตั้งค่าเกียรติบัตรเฉพาะแบบประเมิน

${currentSurvey.certificate_template ? 'ใช้รูปภาพเทมเพลตที่อัปโหลดไว้แล้ว' : 'ใช้เทมเพลตเริ่มต้นของระบบ'} ${currentSurvey.certificate_template ? `` : ''}
มิลลิเมตร (mm)
(ค่าปกติคือ 82.5 มม.) วัดจากขอบบนสุดของกระดาษ
มิลลิเมตร (mm)
(ค่าปกติคือ 190.5 มม.) วัดจากขอบบนสุดของกระดาษ
`; document.getElementById('editorContent').innerHTML = html; const container = document.getElementById('sectionsContainer'); (currentSurvey.sections || []).forEach((section, si) => { container.insertAdjacentHTML('beforeend', buildSectionUI(si, section)); }); } /* ============================================================ SECTION ============================================================ */ function buildSectionUI(si, section) { // Build headings HTML let headingsHTML = ''; (section.headings || []).forEach((heading, hi) => { headingsHTML += buildHeadingUI(si, hi, heading); }); // Build loose questions (not in any heading) HTML let looseQuestionsHTML = ''; (section.questions || []).forEach((q, qi) => { looseQuestionsHTML += buildQuestionUI(si, null, qi, q); }); return `
${headingsHTML}
${looseQuestionsHTML ? `
📋 คำถามทั่วไป (ไม่อยู่ในหัวข้อย่อย)
` : ''} ${looseQuestionsHTML}
`; } function addSection() { const si = document.querySelectorAll('[data-section]').length; const html = buildSectionUI(si, { title: `ส่วนที่ ${si+1}`, category: 'rating', headings: [], questions: [] }); document.getElementById('sectionsContainer').insertAdjacentHTML('beforeend', html); markDirty(); } function removeSection(btn) { if (!confirm('ยืนยันลบส่วนนี้พร้อมหัวข้อย่อยและคำถามทั้งหมด?')) return; btn.closest('.card').remove(); markDirty(); } /* ============================================================ HEADING (หัวข้อย่อย) ============================================================ */ function buildHeadingUI(si, hi, heading = {}) { let questionsHTML = ''; (heading.questions || []).forEach((q, qi) => { questionsHTML += buildQuestionUI(si, hi, qi, q); }); return `
📑
${questionsHTML}
`; } function addHeading(btn) { const sectionEl = btn.closest('[data-section]'); const headingsContainer = sectionEl.querySelector('.headings-container'); const hi = headingsContainer.querySelectorAll('.heading-block').length; const si = parseInt(sectionEl.dataset.section); const html = buildHeadingUI(si, hi, { title: '', description: '', questions: [] }); headingsContainer.insertAdjacentHTML('beforeend', html); // Focus on the title input const newHeading = headingsContainer.lastElementChild; const titleInput = newHeading.querySelector('.heading-title-input'); if (titleInput) titleInput.focus(); markDirty(); } function removeHeading(btn) { if (!confirm('ยืนยันลบหัวข้อย่อยนี้พร้อมคำถามทั้งหมด?')) return; btn.closest('.heading-block').remove(); markDirty(); } /* ============================================================ QUESTION ============================================================ */ function buildQuestionUI(si, hi, qi, q = {}) { const qType = q.question_type || 'radio'; const qText = q.question_text || ''; const qDescription = q.description || ''; const qOptions = Array.isArray(q.options) ? q.options.join('\n') : ''; const showOptions = ['radio', 'checkbox', 'dropdown'].includes(qType); // Context label: which heading or "ทั่วไป" const contextLabel = hi !== null ? `หัวข้อ ${hi+1}` : ''; return `
⋮⋮ คำถาม ${contextLabel ? `(${contextLabel})` : ''}
`; } function addQuestionToHeading(btn) { const headingEl = btn.closest('.heading-block'); const listEl = headingEl.querySelector('.heading-questions-list'); const qi = listEl.querySelectorAll('.question-builder').length; const si = parseInt(headingEl.closest('[data-section]').dataset.section); const hi = parseInt(headingEl.dataset.heading); const html = buildQuestionUI(si, hi, qi); listEl.insertAdjacentHTML('beforeend', html); reindexQuestions(listEl); markDirty(); } function addLooseQuestion(btn) { const sectionEl = btn.closest('[data-section]'); const looseContainer = sectionEl.querySelector('.loose-questions-container'); const si = parseInt(sectionEl.dataset.section); const qi = looseContainer.querySelectorAll('.question-builder').length; // Add label if first loose question if (qi === 0) { looseContainer.insertAdjacentHTML('afterbegin', `
📋 คำถามทั่วไป (ไม่อยู่ในหัวข้อย่อย)
` ); } const html = buildQuestionUI(si, null, qi); looseContainer.insertAdjacentHTML('beforeend', html); reindexQuestions(looseContainer); markDirty(); } function removeQuestion(btn) { if (!confirm('ยืนยันลบคำถามนี้?')) return; const container = btn.closest('.heading-questions-list') || btn.closest('.loose-questions-container'); btn.closest('.question-builder').remove(); if (container) reindexQuestions(container); markDirty(); } function reindexQuestions(container) { if (!container) return; container.querySelectorAll('.question-builder').forEach((qEl, idx) => { const label = qEl.querySelector('.q-number-label'); if (label) label.textContent = `คำถาม`; }); } function toggleOptions(select) { const group = select.closest('.question-builder').querySelector('.q-options-group'); if (['radio', 'checkbox', 'dropdown'].includes(select.value)) { group.style.display = 'block'; } else { group.style.display = 'none'; } } /* ============================================================ SAVE — อ่าน DOM แปลงเป็น JSON แล้วส่ง API ============================================================ */ async function saveSurvey() { if (!currentSurvey) return; const titleEl = document.getElementById('edit-survey-title'); const title = titleEl ? titleEl.value.trim() : currentSurvey.title; if (!title) { Toast.error('กรุณาระบุชื่อแบบสอบถาม'); return; } const description = document.getElementById('edit-survey-desc')?.value || ''; const hasCertificate = document.getElementById('edit-survey-cert')?.checked ? 1 : 0; const sections = []; document.querySelectorAll('[data-section]').forEach((sectionEl, si) => { const sTitle = sectionEl.querySelector('.section-title-input')?.value?.trim() || `ส่วนที่ ${si+1}`; const sCategory = sectionEl.querySelector('.section-category-select')?.value || 'rating'; // Collect headings and their questions const headings = []; sectionEl.querySelectorAll('.heading-block').forEach((headingEl, hi) => { const hTitle = headingEl.querySelector('.heading-title-input')?.value?.trim() || ''; const hDesc = headingEl.querySelector('.heading-desc-input')?.value?.trim() || ''; const hQuestions = collectQuestions(headingEl.querySelector('.heading-questions-list')); if (hTitle) { headings.push({ title: hTitle, description: hDesc || null, order_num: hi, questions: hQuestions }); } }); // Collect loose questions (not in any heading) const looseQuestions = collectQuestions(sectionEl.querySelector('.loose-questions-container')); sections.push({ section_number: si + 1, title: sTitle, category: sCategory, headings: headings, questions: looseQuestions }); }); const setSaveButtonsLoading = (loading) => { const btns = [document.getElementById('saveSurveyBtnTop'), document.getElementById('saveSurveyBtnBottom')]; btns.forEach(btn => { if (btn) { btn.disabled = loading; btn.innerHTML = loading ? ' กำลังบันทึก...' : '💾 บันทึกการเปลี่ยนแปลง'; } }); }; try { setSaveButtonsLoading(true); const certificateTemplate = document.getElementById('edit-survey-cert-template-path')?.value || null; const certNameY = parseFloat(document.getElementById('edit-survey-cert-name-y')?.value || 82.5); const certCodeY = parseFloat(document.getElementById('edit-survey-cert-code-y')?.value || 190.5); await API.post('surveys.php?action=update', { id: currentSurvey.id, title, description, has_certificate: hasCertificate, certificate_template: certificateTemplate, cert_name_y: certNameY, cert_code_y: certCodeY, sections }); Toast.success('บันทึกการแก้ไขเรียบร้อยแล้ว'); isDirty = false; const dirtyIndicator = document.getElementById('saveStatusIndicator'); if (dirtyIndicator) dirtyIndicator.style.display = 'none'; // Update survey title display in header const headerTitleEl = document.getElementById('surveyTitleDisplay'); if (headerTitleEl) headerTitleEl.textContent = title; } catch (err) { Toast.error(err.message || 'บันทึกล้มเหลว'); } finally { setSaveButtonsLoading(false); } } function collectQuestions(container) { if (!container) return []; const questions = []; container.querySelectorAll('.question-builder').forEach((qEl, qi) => { const qText = qEl.querySelector('.q-text-input')?.value || ''; const qDescription = qEl.querySelector('.q-desc-input')?.value || ''; const qType = qEl.querySelector('.q-type-select')?.value || 'radio'; const qOptionsRaw = qEl.querySelector('.q-options-input')?.value || ''; const options = qOptionsRaw.split('\n').map(o => o.trim()).filter(o => o !== ''); if (qText.trim()) { questions.push({ question_text: qText.trim(), description: qDescription.trim() || null, question_type: qType, order_num: qi, is_required: 1, options: options.length > 0 ? options : null }); } }); return questions; } /* ============================================================ UTILITY FUNCTIONS & SHORTCUTS ============================================================ */ function markDirty() { isDirty = true; const dirtyIndicator = document.getElementById('saveStatusIndicator'); if (dirtyIndicator) dirtyIndicator.style.display = 'inline-flex'; } function closeEditor() { if (isDirty) { if (!confirm('มีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก ยืนยันปิดหรือไม่?')) return; } if (window.history.length > 1) { window.history.back(); } else { window.close(); } } function previewSurvey() { if (!currentSurvey) return; const basePath = window.location.pathname.includes('/survey') ? '/survey' : ''; window.open(`${basePath}/respond.php?link=${currentSurvey.unique_link}`, '_blank'); } // Keyboard shortcut: Ctrl+S / Cmd+S to save document.addEventListener('keydown', (e) => { if ((e.ctrlKey || e.metaKey) && e.key === 's') { e.preventDefault(); saveSurvey(); } }); // Warn before leave if dirty window.addEventListener('beforeunload', (e) => { if (isDirty) { e.preventDefault(); e.returnValue = ''; } }); function toggleCertPanel() { const isChecked = document.getElementById('edit-survey-cert').checked; const panel = document.getElementById('cert-config-panel'); if (panel) { panel.style.display = isChecked ? 'block' : 'none'; } } async function uploadCertTemplate(input) { if (!input.files || input.files.length === 0) return; const file = input.files[0]; const statusEl = document.getElementById('cert-upload-status'); statusEl.textContent = '⌛ กำลังอัปโหลดไฟล์...'; statusEl.style.color = '#2563eb'; const formData = new FormData(); formData.append('template_image', file); try { const basePath = window.location.pathname.includes('/survey') ? '/survey' : ''; const res = await fetch(`${basePath}/api/surveys.php?action=uploadTemplate`, { method: 'POST', body: formData }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'การอัปโหลดล้มเหลว'); document.getElementById('edit-survey-cert-template-path').value = data.template_path; statusEl.textContent = '✅ อัปโหลดเทมเพลตสำเร็จ'; statusEl.style.color = '#16a34a'; // Update preview const previewImg = document.getElementById('cert-template-preview'); const previewWrapper = document.getElementById('cert-preview-wrapper'); previewImg.src = (basePath ? `${basePath}/` : '/') + data.template_path; previewWrapper.style.display = 'block'; // Add dynamic delete button if it doesn't exist if (!document.getElementById('cert-delete-btn')) { const btnHTML = ``; input.parentElement.insertAdjacentHTML('beforeend', btnHTML); } markDirty(); } catch (err) { statusEl.textContent = '❌ ' + err.message; statusEl.style.color = '#dc2626'; } } function resetCertTemplate() { document.getElementById('edit-survey-cert-template-path').value = ''; document.getElementById('cert-upload-status').textContent = 'ใช้เทมเพลตเริ่มต้นของระบบ'; document.getElementById('cert-upload-status').style.color = '#6b7280'; document.getElementById('cert-preview-wrapper').style.display = 'none'; document.getElementById('cert-template-preview').src = ''; document.getElementById('edit-survey-cert-file').value = ''; const deleteBtn = document.getElementById('cert-delete-btn'); if (deleteBtn) deleteBtn.remove(); markDirty(); } document.addEventListener('DOMContentLoaded', initEditor);