하이라이트 색상 문제 해결 및 다중 하이라이트 렌더링 개선
주요 수정사항: - 하이라이트 생성 시 color → highlight_color 필드명 수정으로 색상 전달 문제 해결 - 분홍색을 더 연하게 변경하여 글씨 가독성 향상 - 다중 하이라이트 렌더링을 위아래 균등 분할로 개선 - CSS highlight-span 클래스 추가 및 색상 적용 강화 - 하이라이트 생성/렌더링 과정에 상세한 디버깅 로그 추가 UI 개선: - 단일 하이라이트: 선택한 색상으로 정확히 표시 - 다중 하이라이트: 위아래로 균등하게 색상 분할 표시 - 메모 입력 모달에서 선택된 텍스트 표시 개선 버그 수정: - 프론트엔드-백엔드 API 스키마 불일치 해결 - CSS 스타일 우선순위 문제 해결 - 하이라이트 색상이 노랑색으로만 표시되던 문제 해결
This commit is contained in:
268
frontend/static/js/viewer/features/bookmark-manager.js
Normal file
268
frontend/static/js/viewer/features/bookmark-manager.js
Normal file
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* BookmarkManager 모듈
|
||||
* 북마크 관리
|
||||
*/
|
||||
class BookmarkManager {
|
||||
constructor(api) {
|
||||
this.api = api;
|
||||
// 캐싱된 API 사용 (사용 가능한 경우)
|
||||
this.cachedApi = window.cachedApi || api;
|
||||
this.bookmarks = [];
|
||||
this.bookmarkForm = {
|
||||
title: '',
|
||||
description: ''
|
||||
};
|
||||
this.editingBookmark = null;
|
||||
this.currentScrollPosition = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 데이터 로드
|
||||
*/
|
||||
async loadBookmarks(documentId) {
|
||||
try {
|
||||
this.bookmarks = await this.cachedApi.get('/bookmarks', { document_id: documentId }, { category: 'bookmarks' }).catch(() => []);
|
||||
return this.bookmarks || [];
|
||||
} catch (error) {
|
||||
console.error('북마크 로드 실패:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 추가
|
||||
*/
|
||||
async addBookmark(document) {
|
||||
const scrollPosition = window.scrollY;
|
||||
this.bookmarkForm = {
|
||||
title: `${document.title} - ${new Date().toLocaleString()}`,
|
||||
description: ''
|
||||
};
|
||||
this.currentScrollPosition = scrollPosition;
|
||||
|
||||
// ViewerCore의 모달 상태 업데이트
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.showBookmarkModal = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 편집
|
||||
*/
|
||||
editBookmark(bookmark) {
|
||||
this.editingBookmark = bookmark;
|
||||
this.bookmarkForm = {
|
||||
title: bookmark.title,
|
||||
description: bookmark.description || ''
|
||||
};
|
||||
|
||||
// ViewerCore의 모달 상태 업데이트
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.showBookmarkModal = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 저장
|
||||
*/
|
||||
async saveBookmark(documentId) {
|
||||
try {
|
||||
// ViewerCore의 로딩 상태 업데이트
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.bookmarkLoading = true;
|
||||
}
|
||||
|
||||
const bookmarkData = {
|
||||
title: this.bookmarkForm.title,
|
||||
description: this.bookmarkForm.description,
|
||||
scroll_position: this.currentScrollPosition || 0
|
||||
};
|
||||
|
||||
if (this.editingBookmark) {
|
||||
// 북마크 수정
|
||||
const updatedBookmark = await this.api.updateBookmark(this.editingBookmark.id, bookmarkData);
|
||||
const index = this.bookmarks.findIndex(b => b.id === this.editingBookmark.id);
|
||||
if (index !== -1) {
|
||||
this.bookmarks[index] = updatedBookmark;
|
||||
}
|
||||
} else {
|
||||
// 새 북마크 생성
|
||||
bookmarkData.document_id = documentId;
|
||||
const newBookmark = await this.api.createBookmark(bookmarkData);
|
||||
this.bookmarks.push(newBookmark);
|
||||
}
|
||||
|
||||
this.closeBookmarkModal();
|
||||
console.log('북마크 저장 완료');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to save bookmark:', error);
|
||||
alert('북마크 저장에 실패했습니다');
|
||||
} finally {
|
||||
// ViewerCore의 로딩 상태 업데이트
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.bookmarkLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 삭제
|
||||
*/
|
||||
async deleteBookmark(bookmarkId) {
|
||||
if (!confirm('이 북마크를 삭제하시겠습니까?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.api.deleteBookmark(bookmarkId);
|
||||
this.bookmarks = this.bookmarks.filter(b => b.id !== bookmarkId);
|
||||
console.log('북마크 삭제 완료:', bookmarkId);
|
||||
} catch (error) {
|
||||
console.error('Failed to delete bookmark:', error);
|
||||
alert('북마크 삭제에 실패했습니다');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크로 스크롤
|
||||
*/
|
||||
scrollToBookmark(bookmark) {
|
||||
window.scrollTo({
|
||||
top: bookmark.scroll_position,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 모달 닫기
|
||||
*/
|
||||
closeBookmarkModal() {
|
||||
this.editingBookmark = null;
|
||||
this.bookmarkForm = { title: '', description: '' };
|
||||
this.currentScrollPosition = null;
|
||||
|
||||
// ViewerCore의 모달 상태 업데이트
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.showBookmarkModal = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 선택된 텍스트로 북마크 생성
|
||||
*/
|
||||
async createBookmarkFromSelection(documentId, selectedText, selectedRange) {
|
||||
if (!selectedText || !selectedRange) return;
|
||||
|
||||
try {
|
||||
// 하이라이트 생성 (북마크는 주황색)
|
||||
const highlightData = await this.createHighlight(selectedText, selectedRange, '#FFA500');
|
||||
|
||||
// 북마크 생성
|
||||
const bookmarkData = {
|
||||
highlight_id: highlightData.id,
|
||||
title: selectedText.substring(0, 50) + (selectedText.length > 50 ? '...' : ''),
|
||||
description: `선택된 텍스트: "${selectedText}"`
|
||||
};
|
||||
|
||||
const bookmark = await this.api.createBookmark(documentId, bookmarkData);
|
||||
this.bookmarks.push(bookmark);
|
||||
|
||||
console.log('선택 텍스트 북마크 생성 완료:', bookmark);
|
||||
alert('북마크가 생성되었습니다.');
|
||||
|
||||
} catch (error) {
|
||||
console.error('북마크 생성 실패:', error);
|
||||
alert('북마크 생성에 실패했습니다: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 하이라이트 생성 (북마크용)
|
||||
* HighlightManager와 연동
|
||||
*/
|
||||
async createHighlight(selectedText, selectedRange, color) {
|
||||
try {
|
||||
const viewerInstance = window.documentViewerInstance;
|
||||
if (viewerInstance && viewerInstance.highlightManager) {
|
||||
// HighlightManager의 상태 설정
|
||||
viewerInstance.highlightManager.selectedText = selectedText;
|
||||
viewerInstance.highlightManager.selectedRange = selectedRange;
|
||||
viewerInstance.highlightManager.selectedHighlightColor = color;
|
||||
|
||||
// ViewerCore의 상태도 동기화
|
||||
viewerInstance.selectedText = selectedText;
|
||||
viewerInstance.selectedRange = selectedRange;
|
||||
viewerInstance.selectedHighlightColor = color;
|
||||
|
||||
// HighlightManager의 createHighlight 호출
|
||||
await viewerInstance.highlightManager.createHighlight();
|
||||
|
||||
// 생성된 하이라이트 찾기 (가장 최근 생성된 것)
|
||||
const highlights = viewerInstance.highlightManager.highlights;
|
||||
if (highlights && highlights.length > 0) {
|
||||
return highlights[highlights.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// 폴백: 간단한 하이라이트 데이터 반환
|
||||
console.warn('HighlightManager 연동 실패, 폴백 데이터 사용');
|
||||
return {
|
||||
id: Date.now().toString(),
|
||||
selected_text: selectedText,
|
||||
color: color,
|
||||
start_offset: 0,
|
||||
end_offset: selectedText.length
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('하이라이트 생성 실패:', error);
|
||||
|
||||
// 폴백: 간단한 하이라이트 데이터 반환
|
||||
return {
|
||||
id: Date.now().toString(),
|
||||
selected_text: selectedText,
|
||||
color: color,
|
||||
start_offset: 0,
|
||||
end_offset: selectedText.length
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 모드 활성화
|
||||
*/
|
||||
activateBookmarkMode() {
|
||||
console.log('🔖 북마크 모드 활성화');
|
||||
|
||||
// 현재 선택된 텍스트가 있는지 확인
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount > 0 && !selection.isCollapsed) {
|
||||
const selectedText = selection.toString().trim();
|
||||
if (selectedText.length > 0) {
|
||||
// ViewerCore의 선택된 텍스트 상태 업데이트
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.selectedText = selectedText;
|
||||
window.documentViewerInstance.selectedRange = selection.getRangeAt(0);
|
||||
}
|
||||
this.createBookmarkFromSelection(
|
||||
window.documentViewerInstance?.documentId,
|
||||
selectedText,
|
||||
selection.getRangeAt(0)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 텍스트 선택 모드 활성화
|
||||
console.log('📝 텍스트 선택 모드 활성화');
|
||||
if (window.documentViewerInstance) {
|
||||
window.documentViewerInstance.activeMode = 'bookmark';
|
||||
window.documentViewerInstance.showSelectionMessage('텍스트를 선택하세요.');
|
||||
window.documentViewerInstance.setupTextSelectionListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 전역으로 내보내기
|
||||
window.BookmarkManager = BookmarkManager;
|
||||
Reference in New Issue
Block a user