// DOM 요소 const linkTitleInput = document.getElementById('linkTitle'); const linkUrlInput = document.getElementById('linkUrl'); const addBtn = document.getElementById('addBtn'); const linksContainer = document.getElementById('linksContainer'); // 링크 목록을 저장하고 불러오기 let links = []; // 초기 로드 loadLinks(); // 이벤트 리스너 addBtn.addEventListener('click', addLink); linkTitleInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') addLink(); }); linkUrlInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') addLink(); }); // 링크 추가 함수 function addLink() { const title = linkTitleInput.value.trim(); const url = linkUrlInput.value.trim(); if (!title || !url) { alert('제목과 URL을 모두 입력해주세요.'); return; } // URL 형식 검증 (간단한 http/https 체크) if (!url.startsWith('http://') && !url.startsWith('https://')) { alert('올바른 URL 형식을 입력해주세요. (\'http://\' 또는 \'https://\'로 시작)'); return; } const newLink = { id: Date.now(), title: title, url: url }; links.push(newLink); saveLinks(); renderLinks(); // 입력 필드 초기화 linkTitleInput.value = ''; linkUrlInput.value = ''; linkTitleInput.focus(); } // 링크 삭제 함수 function deleteLink(id) { if (confirm('이 링크를 삭제하시겠습니까?')) { links = links.filter(link => link.id !== id); saveLinks(); renderLinks(); } } // 링크로 이동 함수 function navigateToLink(url) { window.location.href = url; } // 링크 렌더링 함수 function renderLinks() { linksContainer.innerHTML = ''; if (links.length === 0) { linksContainer.innerHTML = `
저장된 링크가 없습니다
위에서 자주 방문하는 사이트를 추가해보세요${escapeHtml(link.url)}
`; // 삭제 버튼 이벤트 리스너 const deleteBtn = linkCard.querySelector('.delete-btn'); deleteBtn.addEventListener('click', (e) => { e.stopPropagation(); // 카드 클릭 이벤트 전파 방지 deleteLink(link.id); }); // 카드 클릭 시 링크로 이동 (삭제 버튼 제외) linkCard.addEventListener('click', (e) => { if (!e.target.classList.contains('delete-btn')) { navigateToLink(link.url); } }); // 드래그 앤 드롭 이벤트 linkCard.addEventListener('dragstart', handleDragStart); linkCard.addEventListener('dragover', handleDragOver); linkCard.addEventListener('drop', handleDrop); linkCard.addEventListener('dragenter', handleDragEnter); linkCard.addEventListener('dragleave', handleDragLeave); linkCard.addEventListener('dragend', handleDragEnd); linksContainer.appendChild(linkCard); }); } // Chrome Storage에 저장 function saveLinks() { chrome.storage.sync.set({ links: links }, () => { console.log('Links saved'); }); } // Chrome Storage에서 불러오기 function loadLinks() { chrome.storage.sync.get(['links'], (result) => { if (result.links) { links = result.links; } else { // 기본 링크 예시 (선택사항) links = [ { id: 1, title: 'Google', url: 'https://www.google.com' }, { id: 2, title: 'YouTube', url: 'https://www.youtube.com' }, { id: 3, title: 'GitHub', url: 'https://github.com' } ]; saveLinks(); } renderLinks(); }); } // XSS 방지를 위한 HTML 이스케이프 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 드래그 앤 드롭 관련 변수 let draggedElement = null; // 드래그 시작 function handleDragStart(e) { draggedElement = this; this.classList.add('dragging'); e.dataTransfer.effectAllowed = 'move'; } // 드래그 오버 function handleDragOver(e) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; return false; } // 드래그 진입 function handleDragEnter(e) { if (this !== draggedElement) { this.classList.add('drag-over'); } } // 드래그 떠남 function handleDragLeave(e) { this.classList.remove('drag-over'); } // 드롭 function handleDrop(e) { e.stopPropagation(); e.preventDefault(); if (draggedElement !== this) { const fromIndex = parseInt(draggedElement.dataset.index); const toIndex = parseInt(this.dataset.index); // 배열에서 항목 이동 const movedItem = links.splice(fromIndex, 1)[0]; links.splice(toIndex, 0, movedItem); saveLinks(); renderLinks(); } this.classList.remove('drag-over'); return false; } // 드래그 종료 function handleDragEnd(e) { this.classList.remove('dragging'); // 모든 drag-over 클래스 제거 document.querySelectorAll('.link-card').forEach(card => { card.classList.remove('drag-over'); }); }