first commit 2
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
/**
|
||||
* 템플릿 작성/수정 폼 JavaScript
|
||||
*/
|
||||
|
||||
let questionIndex = 0;
|
||||
|
||||
// 페이지 로드 시 초기화
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initTemplateForm();
|
||||
});
|
||||
|
||||
function initTemplateForm() {
|
||||
// 초기 데이터 설정
|
||||
if (window.templateFormData) {
|
||||
questionIndex = window.templateFormData.questionIndex;
|
||||
}
|
||||
|
||||
// 폼 검증 이벤트
|
||||
initFormValidation();
|
||||
|
||||
// 기존 질문들의 타입에 따라 옵션 표시
|
||||
document.querySelectorAll('.question-type-select').forEach(select => {
|
||||
toggleOptions(select.closest('.question-item').dataset.index);
|
||||
});
|
||||
}
|
||||
|
||||
function addQuestion() {
|
||||
const container = document.getElementById('questionsContainer');
|
||||
const emptyState = document.getElementById('emptyQuestions');
|
||||
|
||||
if (emptyState) {
|
||||
emptyState.remove();
|
||||
}
|
||||
|
||||
const questionHtml = `
|
||||
<div class="question-item" data-index="${questionIndex}">
|
||||
<div class="question-header">
|
||||
<div class="question-number">${questionIndex + 1}</div>
|
||||
<div class="question-title-text">질문 ${questionIndex + 1}</div>
|
||||
<div class="question-actions">
|
||||
<button type="button" class="btn-sm btn-secondary" onclick="moveQuestion(${questionIndex}, 'up')">
|
||||
<i class="fa fa-arrow-up"></i>
|
||||
</button>
|
||||
<button type="button" class="btn-sm btn-secondary" onclick="moveQuestion(${questionIndex}, 'down')">
|
||||
<i class="fa fa-arrow-down"></i>
|
||||
</button>
|
||||
<button type="button" class="btn-sm btn-danger" onclick="removeQuestion(${questionIndex})">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">질문 제목</label>
|
||||
<input type="text" name="questions[${questionIndex}][stq_title]" class="form-control"
|
||||
placeholder="질문을 입력하세요" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group question-type-group">
|
||||
<label class="form-label">질문 유형</label>
|
||||
<select name="questions[${questionIndex}][stq_type]" class="form-control form-select question-type-select"
|
||||
onchange="toggleOptions(${questionIndex})">
|
||||
<option value="text">단답형</option>
|
||||
<option value="textarea">장문형</option>
|
||||
<option value="radio">객관식(단일)</option>
|
||||
<option value="checkbox">객관식(다중)</option>
|
||||
<option value="select">드롭다운</option>
|
||||
<option value="rating">평점</option>
|
||||
<option value="date">날짜</option>
|
||||
<option value="email">이메일</option>
|
||||
<option value="number">숫자</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">질문 설명 (선택사항)</label>
|
||||
<textarea name="questions[${questionIndex}][stq_description]" class="form-control" rows="2"
|
||||
placeholder="질문에 대한 추가 설명"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" name="questions[${questionIndex}][stq_required]" value="1">
|
||||
필수 질문
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.insertAdjacentHTML('beforeend', questionHtml);
|
||||
questionIndex++;
|
||||
updateQuestionNumbers();
|
||||
}
|
||||
|
||||
function removeQuestion(index) {
|
||||
if (confirm('이 질문을 삭제하시겠습니까?')) {
|
||||
const questionItem = document.querySelector(`[data-index="${index}"]`);
|
||||
questionItem.remove();
|
||||
|
||||
const remainingQuestions = document.querySelectorAll('.question-item');
|
||||
if (remainingQuestions.length === 0) {
|
||||
const container = document.getElementById('questionsContainer');
|
||||
container.innerHTML = `
|
||||
<div class="empty-questions" id="emptyQuestions">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
<h3>질문을 추가해주세요</h3>
|
||||
<p>아래 버튼을 클릭하여 첫 번째 질문을 만들어보세요.</p>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
updateQuestionNumbers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function moveQuestion(index, direction) {
|
||||
const questionItem = document.querySelector(`[data-index="${index}"]`);
|
||||
const container = document.getElementById('questionsContainer');
|
||||
|
||||
if (direction === 'up' && questionItem.previousElementSibling) {
|
||||
container.insertBefore(questionItem, questionItem.previousElementSibling);
|
||||
} else if (direction === 'down' && questionItem.nextElementSibling) {
|
||||
container.insertBefore(questionItem.nextElementSibling, questionItem);
|
||||
}
|
||||
|
||||
updateQuestionNumbers();
|
||||
}
|
||||
|
||||
function updateQuestionNumbers() {
|
||||
const questions = document.querySelectorAll('.question-item');
|
||||
questions.forEach((question, index) => {
|
||||
const numberElement = question.querySelector('.question-number');
|
||||
const titleElement = question.querySelector('.question-title-text');
|
||||
|
||||
numberElement.textContent = index + 1;
|
||||
titleElement.textContent = `질문 ${index + 1}`;
|
||||
|
||||
// data-index 업데이트
|
||||
question.dataset.index = index;
|
||||
|
||||
// input name 속성 업데이트
|
||||
const inputs = question.querySelectorAll('input, textarea, select');
|
||||
inputs.forEach(input => {
|
||||
if (input.name && input.name.includes('questions[')) {
|
||||
input.name = input.name.replace(/questions\[\d+\]/, `questions[${index}]`);
|
||||
}
|
||||
});
|
||||
|
||||
// 옵션 컨테이너 ID 업데이트
|
||||
const optionsContainer = question.querySelector('.options-container');
|
||||
if (optionsContainer) {
|
||||
optionsContainer.id = `optionsContainer${index}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toggleOptions(index) {
|
||||
const questionItem = document.querySelector(`[data-index="${index}"]`);
|
||||
const typeSelect = questionItem.querySelector('.question-type-select');
|
||||
const selectedType = typeSelect.value;
|
||||
|
||||
// 기존 옵션 컨테이너 제거
|
||||
const existingOptions = questionItem.querySelector('.options-container');
|
||||
if (existingOptions) {
|
||||
existingOptions.remove();
|
||||
}
|
||||
|
||||
// 객관식 질문인 경우 옵션 컨테이너 추가
|
||||
if (['radio', 'checkbox', 'select'].includes(selectedType)) {
|
||||
const optionsHtml = `
|
||||
<div class="options-container" id="optionsContainer${index}">
|
||||
<label class="form-label">선택 옵션</label>
|
||||
<div class="option-item">
|
||||
<input type="text" name="questions[${index}][options][]"
|
||||
class="form-control option-input"
|
||||
placeholder="옵션을 입력하세요">
|
||||
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn-add-option" onclick="addOption(${index})">
|
||||
<i class="fa fa-plus"></i> 옵션 추가
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
questionItem.insertAdjacentHTML('beforeend', optionsHtml);
|
||||
}
|
||||
}
|
||||
|
||||
function addOption(questionIndex) {
|
||||
const container = document.getElementById(`optionsContainer${questionIndex}`);
|
||||
const addButton = container.querySelector('.btn-add-option');
|
||||
|
||||
const optionHtml = `
|
||||
<div class="option-item">
|
||||
<input type="text" name="questions[${questionIndex}][options][]"
|
||||
class="form-control option-input"
|
||||
placeholder="옵션을 입력하세요">
|
||||
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
addButton.insertAdjacentHTML('beforebegin', optionHtml);
|
||||
}
|
||||
|
||||
function removeOption(button) {
|
||||
const optionsContainer = button.closest('.options-container');
|
||||
const optionItems = optionsContainer.querySelectorAll('.option-item');
|
||||
|
||||
if (optionItems.length > 1) {
|
||||
button.parentElement.remove();
|
||||
} else {
|
||||
alert('최소 1개의 옵션이 필요합니다.');
|
||||
}
|
||||
}
|
||||
|
||||
// 폼 검증
|
||||
function initFormValidation() {
|
||||
document.querySelector('form[name="templateForm"]').addEventListener('submit', function(e) {
|
||||
const templateName = document.querySelector('input[name="st_name"]').value.trim();
|
||||
if (!templateName) {
|
||||
alert('템플릿 이름을 입력해주세요.');
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const questions = document.querySelectorAll('.question-item');
|
||||
if (questions.length === 0) {
|
||||
alert('최소 1개 이상의 질문을 추가해주세요.');
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
// 각 질문의 제목 검증
|
||||
let hasEmptyTitle = false;
|
||||
questions.forEach((question, index) => {
|
||||
const titleInput = question.querySelector('input[name*="[stq_title]"]');
|
||||
if (!titleInput.value.trim()) {
|
||||
alert(`질문 ${index + 1}의 제목을 입력해주세요.`);
|
||||
hasEmptyTitle = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasEmptyTitle) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
// 객관식 질문의 옵션 검증
|
||||
let hasEmptyOptions = false;
|
||||
questions.forEach((question, index) => {
|
||||
const typeSelect = question.querySelector('.question-type-select');
|
||||
const selectedType = typeSelect.value;
|
||||
|
||||
if (['radio', 'checkbox', 'select'].includes(selectedType)) {
|
||||
const optionInputs = question.querySelectorAll('.option-input');
|
||||
const filledOptions = Array.from(optionInputs).filter(input => input.value.trim());
|
||||
|
||||
if (filledOptions.length < 2) {
|
||||
alert(`질문 ${index + 1}은 최소 2개의 옵션이 필요합니다.`);
|
||||
hasEmptyOptions = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (hasEmptyOptions) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user