Files
new-tab-shortcut/script.js
2025-11-09 15:18:08 +09:00

211 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 = `
<div class="empty-state">
<p>저장된 링크가 없습니다</p>
<small>위에서 자주 방문하는 사이트를 추가해보세요</small>
</div>
`;
return;
}
links.forEach((link, index) => {
const linkCard = document.createElement('div');
linkCard.className = 'link-card';
linkCard.draggable = true;
linkCard.dataset.index = index;
linkCard.innerHTML = `
<button class="delete-btn">×</button>
<h3>${escapeHtml(link.title)}</h3>
<p>${escapeHtml(link.url)}</p>
`;
// 삭제 버튼 이벤트 리스너
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');
});
}