/** * 파일: js/script.js * 설명: Autolinker 프론트엔드 JavaScript 기능 * 작성자: Assistant * 최종수정일: 2024-02-13 * * 이 파일은 키워드 관리 시스템의 프론트엔드 기능을 담당합니다. * - 키워드 CRUD 작업 * - 클릭 추적 * - 폼 검증 * - UI 상호작용 */ //---------------------------------------------------------------------------- // 전역 설정 및 유틸리티 //---------------------------------------------------------------------------- /** * 토스트 메시지 표시 함수 * @param {string} message 표시할 메시지 * @param {string} type 메시지 타입 (success, error, warning, info) */ function showToast(message, type = 'info') { const toast = document.createElement('div'); toast.className = `toast align-items-center text-white bg-${type} border-0`; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); toast.setAttribute('aria-atomic', 'true'); toast.innerHTML = `
${message}
`; const container = document.getElementById('toast-container'); container.appendChild(toast); const bsToast = new bootstrap.Toast(toast); bsToast.show(); // 3초 후 자동 제거 setTimeout(() => { bsToast.hide(); setTimeout(() => toast.remove(), 500); }, 3000); } //---------------------------------------------------------------------------- // 키워드 관리 기능 //---------------------------------------------------------------------------- /** * 키워드 추가 폼 제출 처리 * @param {Event} e 폼 이벤트 */ function handleAddKeyword(e) { e.preventDefault(); const form = e.target; const formData = new FormData(form); formData.append('action', 'add'); const submitButton = form.querySelector('button[type="submit"]'); if (submitButton) { submitButton.disabled = true; } form.submit(); } /** * 키워드 수정 처리 */ function handleEditKeyword(e) { e.preventDefault(); const form = e.target; const formData = new FormData(form); formData.append('action', 'edit'); const submitButton = form.querySelector('button[type="submit"]'); if (submitButton) { submitButton.disabled = true; } form.submit(); } /** * 키워드 수정 폼 제출 처리 * 키워드 수정 모달 실행 * @param {Event} e 폼 이벤트 */ function editKeyword(keywordData) { // 모달 폼에 데이터 설정 document.getElementById('edit_id').value = keywordData.id; document.getElementById('edit_keyword').value = keywordData.keyword; document.getElementById('edit_url').value = keywordData.url; document.getElementById('edit_open_new').checked = keywordData.open_new; // 모달 표시 var editModal = new bootstrap.Modal(document.getElementById('editKeywordModal')); editModal.show(); } /** * 키워드 삭제 처리 * @param {number} id 삭제할 키워드 ID */ function deleteKeyword(id) { if (confirm('정말 이 키워드를 삭제하시겠습니까?')) { // 삭제 폼 생성 및 제출 var form = document.createElement('form'); form.method = 'POST'; form.action = 'process.php'; // hidden 필드 추가 var actionInput = document.createElement('input'); actionInput.type = 'hidden'; actionInput.name = 'action'; actionInput.value = 'delete'; form.appendChild(actionInput); var idInput = document.createElement('input'); idInput.type = 'hidden'; idInput.name = 'id'; idInput.value = id; form.appendChild(idInput); // 폼을 body에 추가하고 제출 document.body.appendChild(form); form.submit(); } } //---------------------------------------------------------------------------- // 폼 검증 및 UI 갱신 //---------------------------------------------------------------------------- /** * 키워드 폼 검증 * @param {FormData} formData 검증할 폼 데이터 * @returns {boolean} 검증 통과 여부 */ function validateKeywordForm(formData) { const keyword = formData.get('keyword'); const url = formData.get('url'); if (!keyword.trim()) { showToast('키워드를 입력해주세요.', 'warning'); return false; } if (!url.trim()) { showToast('URL을 입력해주세요.', 'warning'); return false; } // URL 형식 검증 try { new URL(url); } catch (e) { showToast('올바른 URL 형식이 아닙니다.', 'warning'); return false; } return true; } /** * 키워드 목록 새로고침 */ function refreshKeywordList() { const container = document.getElementById('keyword-list'); const currentPage = new URLSearchParams(window.location.search).get('page') || 1; fetch(`list.php?page=${currentPage}`) .then(response => response.text()) .then(html => { container.innerHTML = html; }) .catch(error => { console.error('Error:', error); showToast('목록 새로고침 실패', 'error'); }); } //---------------------------------------------------------------------------- // 클릭 추적 기능 //---------------------------------------------------------------------------- document.addEventListener('click', function(e) { const link = e.target.closest('a.autolink'); if (!link) return; const keywordId = link.getAttribute('data-keyword-id'); if (!keywordId) return; console.log('Autolink clicked:', keywordId); const formData = new FormData(); formData.append('action', 'log_click'); formData.append('keyword_id', keywordId); // 현재 페이지의 base URL에서 process.php의 경로 구성 const currentPath = window.location.pathname; const processUrl = currentPath.includes('/admin/') ? './process.php' // admin 폴더 내부에서 접근 : BASE_URL + '/admin/process.php'; // 외부에서 접근 console.log('Sending request to:', processUrl); fetch(processUrl, { method: 'POST', body: formData, headers: { 'Accept': 'application/json' } }) .then(response => { if (!response.ok) { return response.text().then(text => { console.error('Server response:', text); throw new Error('Server response was not ok'); }); } return response.json(); }) .then(data => { console.log('Click logged successfully:', data); }) .catch(error => { console.error('Error logging click:', error.message || error); }); }); //---------------------------------------------------------------------------- // 이벤트 리스너 등록 //---------------------------------------------------------------------------- document.addEventListener('DOMContentLoaded', function() { // 폼 제출 이벤트 리스너 const addForm = document.getElementById('addKeywordForm'); if (addForm) { addForm.addEventListener('submit', handleAddKeyword); } const editForm = document.getElementById('editKeywordForm'); if (editForm) { editForm.addEventListener('submit', handleEditKeyword); } // 검색 폼 처리 const searchForm = document.getElementById('searchForm'); if (searchForm) { searchForm.addEventListener('submit', function(e) { e.preventDefault(); const searchInput = this.querySelector('input[name="search"]'); if (searchInput.value.trim()) { this.submit(); } }); } });