이미지 불러오는 식 좀 부탁드립니다. 채택완료
아썸
11년 전
조회 6,969
코멘트스킨 답댓글 부분에 아이콘을 불러오려고 하는데
홈피주소로 대입하면 불러와 지는데 다음의 식으로 불러오면 여러가지 형태로 바꿔봐도
엑박이네요.. img src 부분의 올바른 식은 무엇인지요?



위 세가지 식도 안되네요.
// 댓글 달때 꼬리상대 이름 저장 step 0 - wr_1 by zzzz 20131115
$mm = get_member($list[$i]['wr_1'], 'mb_nick');
if($mm['mb_nick']) {
echo '
';
'; echo ''.$mm['mb_nick'].'';
}
?>
댓글을 작성하려면 로그인이 필요합니다.
답변 2개
채택된 답변
+20 포인트
11년 전
작은따옴표 속에 넣으면 있는 그대로의 문자로 나옵니다
큰따옴표로..
echo "
response.json())
.then(data => {
if (data.success) {
countSpan.textContent = data.good_count;
if (data.user_vote === null) {
// 취소된 경우
textSpan.textContent = '좋아요';
this.classList.remove('bg-blue-100', 'dark:bg-blue-900', 'text-blue-700', 'dark:text-blue-300');
this.classList.add('bg-green-100', 'dark:bg-green-900', 'text-green-700', 'dark:text-green-300', 'hover:bg-green-200', 'dark:hover:bg-green-800');
} else {
// 투표된 경우
textSpan.textContent = '좋아요됨';
this.classList.remove('bg-green-100', 'dark:bg-green-900', 'text-green-700', 'dark:text-green-300', 'hover:bg-green-200', 'dark:hover:bg-green-800');
this.classList.add('bg-blue-100', 'dark:bg-blue-900', 'text-blue-700', 'dark:text-blue-300');
}
console.log('Success message:', data.message);
showMessage(data.message, 'success');
} else {
console.log('Error message:', data.error);
showMessage(data.error || '좋아요에 실패했습니다.', 'error');
}
this.disabled = false;
this.classList.remove('opacity-50');
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
this.disabled = false;
this.classList.remove('opacity-50');
});
});
}
// 싫어요 기능
const voteNogoodBtn = document.getElementById('vote-nogood-btn');
if (voteNogoodBtn) {
voteNogoodBtn.addEventListener('click', function() {
const wrId = this.dataset.wrId;
const countSpan = this.querySelector('.vote-nogood-count');
const textSpan = this.querySelector('.vote-nogood-text');
const isVoted = textSpan.textContent === '싫어요됨';
if (this.disabled) return;
this.disabled = true;
this.classList.add('opacity-50');
fetch(`/questions/${wrId}/vote`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ type: 'nogood' })
})
.then(response => response.json())
.then(data => {
if (data.success) {
countSpan.textContent = data.nogood_count;
if (data.user_vote === null) {
// 취소된 경우
textSpan.textContent = '싫어요';
this.classList.remove('bg-orange-100', 'dark:bg-orange-900', 'text-orange-700', 'dark:text-orange-300');
this.classList.add('bg-red-100', 'dark:bg-red-900', 'text-red-700', 'dark:text-red-300', 'hover:bg-red-200', 'dark:hover:bg-red-800');
} else {
// 투표된 경우
textSpan.textContent = '싫어요됨';
this.classList.remove('bg-red-100', 'dark:bg-red-900', 'text-red-700', 'dark:text-red-300', 'hover:bg-red-200', 'dark:hover:bg-red-800');
this.classList.add('bg-orange-100', 'dark:bg-orange-900', 'text-orange-700', 'dark:text-orange-300');
}
console.log('Success message:', data.message);
showMessage(data.message, 'success');
} else {
console.log('Error message:', data.error);
showMessage(data.error || '싫어요에 실패했습니다.', 'error');
}
this.disabled = false;
this.classList.remove('opacity-50');
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
this.disabled = false;
this.classList.remove('opacity-50');
});
});
}
// 스크랩 기능
const scrapBtn = document.getElementById('scrap-btn');
if (scrapBtn) {
scrapBtn.addEventListener('click', function() {
const wrId = this.dataset.wrId;
const countSpan = this.querySelector('.scrap-count');
this.disabled = true;
this.classList.add('opacity-50');
fetch(`/questions/${wrId}/scrap`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
countSpan.textContent = `(${data.count})`;
const textSpan = this.querySelector('.scrap-text');
const iconSpan = this.querySelector('i');
// 스크랩된 상태로 변경
textSpan.textContent = '스크랩됨';
iconSpan.className = 'fa fa-bookmark mr-1';
this.classList.remove('bg-gray-100', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-200', 'dark:hover:bg-gray-600');
this.classList.add('bg-yellow-100', 'dark:bg-yellow-900', 'text-yellow-700', 'dark:text-yellow-300');
// 스크랩 후 버튼 비활성화
this.disabled = true;
showMessage(data.message, 'success');
} else {
showMessage(data.error || '스크랩에 실패했습니다.', 'error');
}
this.disabled = false;
this.classList.remove('opacity-50');
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
this.disabled = false;
this.classList.remove('opacity-50');
});
});
}
// 신고 기능
document.querySelectorAll('button[id^=qa_singo-]').forEach(button => {
button.addEventListener('click', function() {
const idParts = this.id.split('-');
const bo_table = idParts[1];
const wr_id = idParts[2];
const radios_reason = ["#rdo_reason_ad", "#rdo_reason_ob", "#rdo_reason_ha", "#rdo_reason_etc"];
// 모달 다이얼로그 표시
const modal = document.getElementById('sir_react_singod');
modal.style.display = 'block';
modal.style.position = 'fixed';
modal.style.top = '50%';
modal.style.left = '50%';
modal.style.transform = 'translate(-50%, -50%)';
modal.style.backgroundColor = 'white';
modal.style.padding = '20px';
modal.style.borderRadius = '8px';
modal.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
modal.style.zIndex = '1000';
modal.style.minWidth = '400px';
// 배경 오버레이
const overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
overlay.style.zIndex = '999';
document.body.appendChild(overlay);
// 신고하기 버튼
const reportBtn = document.createElement('button');
reportBtn.textContent = '신고하기';
reportBtn.className = 'px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 mr-2';
reportBtn.addEventListener('click', function() {
let r_checked = false;
let reason = '';
radios_reason.forEach(radioId => {
if (document.querySelector(radioId).checked) {
r_checked = true;
if (radioId === '#rdo_reason_etc') {
const customReason = document.getElementById('sg_reason').value.trim();
if (customReason.length < 10) {
alert('기타 선택시 신고사유를 10글자 이상 입력하십시오.');
return;
}
reason = customReason;
} else {
reason = document.querySelector(radioId).value;
}
}
});
if (!r_checked) {
alert('신고사유를 선택하세요.');
return;
}
// 신고 요청
fetch(`/questions/${wr_id}/singo`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
bo_table: bo_table,
reason: reason,
q_mode: 'singo'
})
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
return;
}
// 모달 닫기
modal.style.display = 'none';
document.body.removeChild(overlay);
// 신고 카운트 업데이트
const countElement = document.querySelector(`#qa_singo-${bo_table}-${wr_id} .singo-count`);
if (countElement) {
countElement.textContent = data.count;
}
// 버튼 비활성화
button.disabled = true;
button.classList.add('opacity-50');
alert(data.message);
})
.catch(error => {
console.error('Error:', error);
alert('신고 처리 중 오류가 발생했습니다.');
});
});
// 취소 버튼
const cancelBtn = document.createElement('button');
cancelBtn.textContent = '취소';
cancelBtn.className = 'px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600';
cancelBtn.addEventListener('click', function() {
modal.style.display = 'none';
document.body.removeChild(overlay);
});
// 기존 버튼들 제거
const existingButtons = modal.querySelectorAll('button');
existingButtons.forEach(btn => btn.remove());
// 버튼들 추가
const buttonContainer = document.createElement('div');
buttonContainer.className = 'mt-4 text-right';
buttonContainer.appendChild(reportBtn);
buttonContainer.appendChild(cancelBtn);
modal.appendChild(buttonContainer);
// 오버레이 클릭 시 닫기
overlay.addEventListener('click', function() {
modal.style.display = 'none';
document.body.removeChild(overlay);
});
});
});
// 공유 기능
const shareBtn = document.getElementById('share-btn');
if (shareBtn) {
shareBtn.addEventListener('click', function() {
const shareModal = document.getElementById('share-modal');
const currentUrl = window.location.href;
const title = document.title;
// SNS 공유 링크 설정
const facebookUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(currentUrl)}`;
const twitterUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(currentUrl)}&text=${encodeURIComponent(title)}`;
document.getElementById('facebook-share').href = facebookUrl;
document.getElementById('twitter-share').href = twitterUrl;
shareModal.classList.remove('hidden');
});
}
// 메시지 표시 함수
});
// 공유 모달 닫기
function closeShareModal() {
document.getElementById('share-modal').classList.add('hidden');
}
// 클립보드에 복사
function copyToClipboard() {
navigator.clipboard.writeText(window.location.href).then(function() {
showMessage('링크가 클립보드에 복사되었습니다.', 'success');
closeShareModal();
});
}
// Image preview function
function previewImage(imageUrl, filename) {
// Create modal overlay
const overlay = document.createElement('div');
overlay.className = 'fixed inset-0 bg-black bg-opacity-75 z-50 flex items-center justify-center p-4';
overlay.onclick = function() {
document.body.removeChild(overlay);
};
// Create modal content
const modal = document.createElement('div');
modal.className = 'bg-white dark:bg-gray-800 rounded-lg max-w-4xl max-h-full overflow-auto';
modal.onclick = function(e) {
e.stopPropagation();
};
modal.innerHTML = `
`;
overlay.appendChild(modal);
document.body.appendChild(overlay);
}
// 메시지 표시 함수
function showMessage(message, type = 'info') {
console.log('showMessage called:', message, type);
// 기존 메시지 제거
const existingMessage = document.querySelector('.message-toast');
if (existingMessage) {
existingMessage.remove();
}
// 새 메시지 생성
const messageDiv = document.createElement('div');
messageDiv.className = 'message-toast fixed top-4 right-4 z-50 px-6 py-3 rounded-lg shadow-lg transition-all duration-300';
if (type === 'success') {
messageDiv.className += ' bg-green-500 text-white';
} else if (type === 'error') {
messageDiv.className += ' bg-red-500 text-white';
} else {
messageDiv.className += ' bg-blue-500 text-white';
}
messageDiv.textContent = message;
document.body.appendChild(messageDiv);
console.log('Message displayed:', messageDiv);
// 3초 후 자동 제거
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.style.opacity = '0';
messageDiv.style.transform = 'translateX(100%)';
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.parentNode.removeChild(messageDiv);
}
}, 300);
}
}, 3000);
}
// 답변 작성 폼 처리
document.addEventListener('DOMContentLoaded', function() {
// 답변 작성 폼
const answerForm = document.getElementById('answer-form-element');
if (answerForm) {
answerForm.addEventListener('submit', function(e) {
e.preventDefault(); // 기본 폼 제출 방지
// 중복 제출 방지
const submitBtn = this.querySelector('button[type="submit"]');
if (submitBtn.disabled) {
return;
}
// 버튼 비활성화
submitBtn.disabled = true;
submitBtn.textContent = '등록 중...';
// CKEditor 내용 가져오기
const content = CKEDITOR.instances.wr_content ? CKEDITOR.instances.wr_content.getData() : '';
// FormData 생성
const formData = new FormData();
formData.append('_token', document.querySelector('input[name="_token"]').value);
formData.append('wr_qa_id', document.querySelector('input[name="wr_qa_id"]').value);
formData.append('wr_content', content);
// AJAX 요청
fetch('https://new-sir.gnuboard.net/questions/answer', {
method: 'POST',
body: formData,
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 성공 메시지 표시
showMessage('답변이 등록되었습니다.', 'success');
// 페이지 새로고침하여 새 답변 표시
window.location.reload();
} else {
// 에러 메시지 표시
showMessage(data.message || '답변 등록 중 오류가 발생했습니다.', 'error');
// 버튼 복원
submitBtn.disabled = false;
submitBtn.textContent = '답변 등록';
}
})
.catch(error => {
console.error('Error:', error);
showMessage('답변 등록 중 오류가 발생했습니다.', 'error');
// 버튼 복원
submitBtn.disabled = false;
submitBtn.textContent = '답변 등록';
});
});
}
// URL 프래그먼트 처리
function handleFragment() {
const hash = window.location.hash;
if (hash === '#new-answer') {
// URL에서 프래그먼트 제거 (히스토리 정리)
history.replaceState(null, null, window.location.pathname + window.location.search);
setTimeout(() => {
// 답변 목록에서 가장 최근 답변 찾기
const answers = document.querySelectorAll('.answer-item');
if (answers.length > 0) {
const lastAnswer = answers[answers.length - 1];
lastAnswer.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
// 새 답변에 하이라이트 효과 추가
lastAnswer.style.backgroundColor = '#fef3c7';
lastAnswer.style.transition = 'background-color 0.3s ease';
setTimeout(() => {
lastAnswer.style.backgroundColor = '';
}, 3000);
}
}, 500);
}
}
// 페이지 로드 시 프래그먼트 처리
handleFragment();
// 해시 변경 이벤트 리스너 (브라우저 뒤로가기/앞으로가기 대응)
window.addEventListener('hashchange', handleFragment);
});
// 답변 좋아요/싫어요 기능
document.addEventListener('DOMContentLoaded', function() {
// 답변 좋아요 버튼
document.querySelectorAll('.vote-good-btn').forEach(button => {
if (button.id !== 'vote-good-btn') { // 질문 좋아요 버튼 제외
button.addEventListener('click', function() {
const wrId = this.dataset.wrId;
const countSpan = this.querySelector('.vote-good-count');
const textSpan = this.querySelector('.vote-good-text');
const isVoted = textSpan.textContent === '좋아요됨';
if (this.disabled) return;
this.disabled = true;
this.classList.add('opacity-50');
fetch(`/questions/${wrId}/vote`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ type: 'good' })
})
.then(response => response.json())
.then(data => {
if (data.success) {
countSpan.textContent = data.good_count;
if (data.user_vote === null) {
// 취소된 경우
textSpan.textContent = '좋아요';
this.classList.remove('bg-blue-100', 'dark:bg-blue-700', 'text-blue-700', 'dark:text-blue-300');
this.classList.add('bg-gray-100', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-200', 'dark:hover:bg-gray-600');
} else {
// 투표된 경우
textSpan.textContent = '좋아요됨';
this.classList.remove('bg-gray-100', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-200', 'dark:hover:bg-gray-600');
this.classList.add('bg-blue-100', 'dark:bg-blue-700', 'text-blue-700', 'dark:text-blue-300');
}
showMessage(data.message, 'success');
} else {
showMessage(data.error || '좋아요에 실패했습니다.', 'error');
}
this.disabled = false;
this.classList.remove('opacity-50');
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
this.disabled = false;
this.classList.remove('opacity-50');
});
});
}
});
// 답변 싫어요 버튼
document.querySelectorAll('.vote-nogood-btn').forEach(button => {
if (button.id !== 'vote-nogood-btn') { // 질문 싫어요 버튼 제외
button.addEventListener('click', function() {
const wrId = this.dataset.wrId;
const countSpan = this.querySelector('.vote-nogood-count');
const textSpan = this.querySelector('.vote-nogood-text');
const isVoted = textSpan.textContent === '싫어요됨';
if (this.disabled) return;
this.disabled = true;
this.classList.add('opacity-50');
fetch(`/questions/${wrId}/vote`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ type: 'nogood' })
})
.then(response => response.json())
.then(data => {
if (data.error === '') {
countSpan.textContent = data.count;
if (data.cancle_vote === 'cancle') {
// 취소된 경우
textSpan.textContent = '싫어요';
this.classList.remove('bg-orange-100', 'dark:bg-orange-700', 'text-orange-700', 'dark:text-orange-300');
this.classList.add('bg-gray-100', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-200', 'dark:hover:bg-gray-600');
} else {
// 투표된 경우
textSpan.textContent = '싫어요됨';
this.classList.remove('bg-gray-100', 'dark:bg-gray-700', 'text-gray-700', 'dark:text-gray-300', 'hover:bg-gray-200', 'dark:hover:bg-gray-600');
this.classList.add('bg-orange-100', 'dark:bg-orange-700', 'text-orange-700', 'dark:text-orange-300');
}
showMessage(data.message, 'success');
} else {
showMessage(data.error || '싫어요에 실패했습니다.', 'error');
}
this.disabled = false;
this.classList.remove('opacity-50');
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
this.disabled = false;
this.classList.remove('opacity-50');
});
});
}
});
// 채택 버튼
document.querySelectorAll('.adopt-btn').forEach(button => {
button.addEventListener('click', function() {
const questionId = this.dataset.questionId;
const answerId = this.dataset.answerId;
if (!confirm('이 답변을 채택하시겠습니까?\n\n채택된 답변은 변경할 수 없습니다.')) {
return;
}
fetch(`/questions/${questionId}/adopt/${answerId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage(data.message, 'success');
// 페이지 새로고침하여 채택 상태 반영
setTimeout(() => {
location.reload();
}, 1500);
} else {
showMessage(data.error || '채택에 실패했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
});
});
});
// 채택 취소 버튼
document.querySelectorAll('.unadopt-btn').forEach(button => {
button.addEventListener('click', function() {
const questionId = this.dataset.questionId;
if (!confirm('채택을 취소하시겠습니까?\n\n채택된 답변 작성자에게 지급된 포인트가 회수됩니다.')) {
return;
}
fetch(`/questions/${questionId}/unadopt`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage(data.message, 'success');
// 페이지 새로고침하여 채택 취소 상태 반영
setTimeout(() => {
location.reload();
}, 1500);
} else {
showMessage(data.error || '채택 취소에 실패했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
});
});
});
// 댓글 작성
document.querySelectorAll('.comment-form-element').forEach(form => {
form.addEventListener('submit', function(e) {
e.preventDefault();
// 중복 제출 방지
const submitBtn = this.querySelector('button[type="submit"]');
if (submitBtn.disabled) {
return;
}
const parentId = this.dataset.parentId;
const content = this.querySelector('textarea[name="wr_content"]').value.trim();
if (!content) {
showMessage('댓글 내용을 입력해주세요.', 'error');
return;
}
// 버튼 비활성화
submitBtn.disabled = true;
submitBtn.textContent = '등록 중...';
const formData = new FormData();
formData.append('wr_qa_id', parentId);
formData.append('wr_content', content);
formData.append('_token', document.querySelector('meta[name="csrf-token"]').getAttribute('content'));
fetch('/questions/comment', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage(data.message, 'success');
// 페이지 새로고침하여 댓글 반영
setTimeout(() => {
location.reload();
}, 1000);
} else {
showMessage(data.error || '댓글 등록에 실패했습니다.', 'error');
// 실패 시 버튼 다시 활성화
submitBtn.disabled = false;
submitBtn.textContent = '댓글 등록';
}
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
// 오류 시 버튼 다시 활성화
submitBtn.disabled = false;
submitBtn.textContent = '댓글 등록';
});
});
});
// 댓글 수정
document.querySelectorAll('.edit-comment-btn').forEach(button => {
button.addEventListener('click', function() {
const commentContainer = this.closest('.relative');
const commentContent = commentContainer.querySelector('.comment-content');
const editForm = commentContainer.querySelector('.comment-edit-form');
const textarea = editForm.querySelector('textarea');
// 편집 모드로 전환
commentContent.classList.add('hidden');
editForm.classList.remove('hidden');
textarea.focus();
});
});
// 댓글 저장
document.querySelectorAll('.comment-save-btn').forEach(button => {
button.addEventListener('click', function() {
const commentId = this.dataset.commentId;
const commentContainer = this.closest('.relative');
const textarea = commentContainer.querySelector('textarea');
const newContent = textarea.value.trim();
if (!newContent) {
showMessage('댓글 내용을 입력해주세요.', 'error');
return;
}
fetch(`/questions/comment/${commentId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
wr_content: newContent
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage(data.message, 'success');
// 페이지 새로고침하여 수정된 댓글 반영
setTimeout(() => {
location.reload();
}, 1000);
} else {
showMessage(data.error || '댓글 수정에 실패했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
});
});
});
// 댓글 수정 취소
document.querySelectorAll('.comment-cancel-btn').forEach(button => {
button.addEventListener('click', function() {
const commentContainer = this.closest('.relative');
const commentContent = commentContainer.querySelector('.comment-content');
const editForm = commentContainer.querySelector('.comment-edit-form');
const textarea = editForm.querySelector('textarea');
// 원래 내용으로 복원
textarea.value = commentContent.textContent.trim();
// 편집 모드 해제
editForm.classList.add('hidden');
commentContent.classList.remove('hidden');
});
});
// 댓글 삭제
document.querySelectorAll('.delete-comment-btn').forEach(button => {
button.addEventListener('click', function() {
const commentId = this.dataset.commentId;
if (!confirm('정말로 이 댓글을 삭제하시겠습니까?')) {
return;
}
fetch(`/questions/comment/${commentId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage(data.message, 'success');
// 페이지 새로고침하여 삭제된 댓글 반영
setTimeout(() => {
location.reload();
}, 1000);
} else {
showMessage(data.error || '댓글 삭제에 실패했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
});
});
});
// 대댓글 답글 버튼 클릭
document.querySelectorAll('.reply-comment-btn').forEach(button => {
button.addEventListener('click', function() {
const commentId = this.getAttribute('data-comment-id');
const commentAuthor = this.getAttribute('data-comment-author');
const replyForm = this.closest('.relative').querySelector('.reply-form');
const replyTarget = replyForm.querySelector('.reply-target');
// 다른 대댓글 폼들 숨기기
document.querySelectorAll('.reply-form').forEach(form => {
if (form !== replyForm) {
form.classList.add('hidden');
}
});
// 현재 대댓글 폼 토글
replyForm.classList.toggle('hidden');
// 답글 대상 표시
replyTarget.textContent = `${commentAuthor}님에게 답글`;
// 폼이 보이면 textarea에 포커스
if (!replyForm.classList.contains('hidden')) {
const textarea = replyForm.querySelector('textarea');
textarea.focus();
}
});
});
// 대댓글 취소 버튼
document.querySelectorAll('.reply-cancel-btn').forEach(button => {
button.addEventListener('click', function() {
const replyForm = this.closest('.reply-form');
const textarea = replyForm.querySelector('textarea');
// 내용 초기화
textarea.value = '';
// 폼 숨기기
replyForm.classList.add('hidden');
});
});
// 대댓글 등록
document.querySelectorAll('.reply-form-element').forEach(form => {
form.addEventListener('submit', function(e) {
e.preventDefault();
// 중복 제출 방지
const submitBtn = this.querySelector('button[type="submit"]');
if (submitBtn.disabled) {
return;
}
const formData = new FormData(this);
const parentId = this.getAttribute('data-parent-id');
const commentId = this.getAttribute('data-comment-id');
const textarea = this.querySelector('textarea[name="wr_content"]');
const content = textarea.value.trim();
if (!content) {
showMessage('답글 내용을 입력해주세요.', 'error');
return;
}
// 버튼 비활성화
submitBtn.disabled = true;
submitBtn.textContent = '등록 중...';
// 답글 대상 정보 추가
formData.append('wr_comment_reply', commentId);
formData.append('wr_qa_id', parentId);
formData.append('parent_id', parentId);
fetch(`/questions/comment`, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage('답글이 등록되었습니다.', 'success');
textarea.value = '';
this.closest('.reply-form').classList.add('hidden');
// 페이지 새로고침으로 새 답글 표시
setTimeout(() => {
location.reload();
}, 1000);
} else {
showMessage(data.error || '답글 등록 중 오류가 발생했습니다.', 'error');
// 실패 시 버튼 다시 활성화
submitBtn.disabled = false;
submitBtn.textContent = '답글 등록';
}
})
.catch(error => {
console.error('Error:', error);
showMessage('네트워크 오류가 발생했습니다.', 'error');
// 오류 시 버튼 다시 활성화
submitBtn.disabled = false;
submitBtn.textContent = '답글 등록';
});
});
});
});
// 프래그먼트 식별자 스크롤 처리
document.addEventListener('DOMContentLoaded', function() {
// URL에 프래그먼트가 있는지 확인
if (window.location.hash) {
const hash = window.location.hash.substring(1); // # 제거
const targetElement = document.getElementById(hash);
if (targetElement) {
// 약간의 지연 후 스크롤 (페이지 로딩 완료 후)
setTimeout(() => {
const headerHeight = 120; // 헤더 높이 + 여백
const elementPosition = targetElement.offsetTop;
const offsetPosition = elementPosition - headerHeight;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}, 100);
}
}
});
// 답변 정렬 기능
document.addEventListener('DOMContentLoaded', function() {
const sortSelect = document.getElementById('qa_sort_select');
if (sortSelect) {
sortSelect.addEventListener('change', function() {
const sortValue = this.value;
const currentUrl = new URL(window.location);
currentUrl.searchParams.set('vsst', sortValue);
currentUrl.searchParams.set('vpage', '1'); // 정렬 변경 시 첫 페이지로
currentUrl.hash = '#qa_answer';
window.location.href = currentUrl.toString();
});
}
});
// 답변 삭제 기능
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.delete-answer-btn').forEach(button => {
button.addEventListener('click', function() {
const answerId = this.getAttribute('data-answer-id');
if (confirm('정말로 이 답변을 삭제하시겠습니까?')) {
fetch(`/questions/${answerId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 답변 요소 제거
const answerElement = document.getElementById(`answer_${answerId}`);
if (answerElement) {
answerElement.remove();
}
// 답변 수 업데이트 (전체 답변 수에서 1 감소)
const answerCountElement = document.querySelector('h2');
if (answerCountElement) {
const currentCount = parseInt(answerCountElement.textContent.match(/\d+/)[0]);
answerCountElement.textContent = `답변 ${currentCount - 1}개`;
}
// 페이지 새로고침 (전체 답변 수와 페이징을 정확히 반영하기 위해)
setTimeout(() => {
window.location.reload();
}, 1000);
showMessage('답변이 삭제되었습니다.', 'success');
} else {
showMessage(data.message || '답변 삭제 중 오류가 발생했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('답변 삭제 중 오류가 발생했습니다.', 'error');
});
}
});
});
});
// 미채택 완료
function closeWithoutAdopt(questionId) {
if (!confirm('답변을 채택하지 않고 질문을 완료하시겠습니까?\n\n이 작업은 취소할 수 없습니다.')) {
return;
}
fetch(`/questions/${questionId}/close-without-adopt`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage('질문이 미채택 완료되었습니다.', 'success');
setTimeout(() => {
window.location.reload();
}, 1500);
} else {
showMessage(data.error || '처리에 실패했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('처리 중 오류가 발생했습니다.', 'error');
});
}
// 재등록
function reregisterQuestion(questionId) {
if (!confirm('이 질문을 재등록하시겠습니까?\n\n재등록하면 새로운 답변을 받을 수 있습니다.')) {
return;
}
fetch(`/questions/${questionId}/reregister`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage('질문이 재등록되었습니다.', 'success');
if (data.redirect) {
setTimeout(() => {
window.location.href = data.redirect;
}, 1500);
} else {
setTimeout(() => {
window.location.reload();
}, 1500);
}
} else {
showMessage(data.error || '처리에 실패했습니다.', 'error');
}
})
.catch(error => {
console.error('Error:', error);
showMessage('처리 중 오류가 발생했습니다.', 'error');
});
}
// Prism.js용 코드 복사 기능
function copyCodePrism(button) {
// 버튼의 부모 요소에서 코드 블록 찾기
const wrapper = button.closest('.code-block-wrapper');
const codeBlock = wrapper.querySelector('code');
const codeText = codeBlock.textContent;
// 클립보드에 복사
navigator.clipboard.writeText(codeText).then(() => {
// 버튼 텍스트 임시 변경
const originalHTML = button.innerHTML;
const originalStyle = {
background: button.style.background,
borderColor: button.style.borderColor,
color: button.style.color
};
button.innerHTML = ' Copied!';
button.style.background = 'rgba(72, 187, 120, 0.7)';
button.style.borderColor = 'rgba(72, 187, 120, 0.9)';
button.style.color = '#fff';
// 2초 후 원래 상태로 복구
setTimeout(() => {
button.innerHTML = originalHTML;
button.style.background = originalStyle.background;
button.style.borderColor = originalStyle.borderColor;
button.style.color = originalStyle.color;
}, 2000);
}).catch(err => {
console.error('Failed to copy code:', err);
// Fallback: 전통적인 복사 방법 사용
const textArea = document.createElement('textarea');
textArea.value = codeText;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
// 성공 표시
const originalHTML = button.innerHTML;
button.innerHTML = '✓ Copied!';
setTimeout(() => {
button.innerHTML = originalHTML;
}, 2000);
} catch (err) {
alert('코드 복사에 실패했습니다.');
}
document.body.removeChild(textArea);
});
}