/** * 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;