모든 기능 복원 및 안정화
- PDF 다운로드 기능 복원 (직접 다운로드 + 연결된 PDF 지원) - 언어 전환 기능 수정 (문서 내장 기능 활용) - 헤더 네비게이션 버튼 구현 (뒤로가기, 목차, 이전/다음 문서) - PDF 매칭 UI 추가 (book-documents.html) - 링크/백링크 렌더링 안정화 - 서적 URL 파라미터 수정 (book_id 지원) 주요 수정사항: - viewer-core.js: PDF 다운로드 로직 개선, 언어 전환 단순화 - book-documents.js/html: PDF 매칭 기능 및 URL 파라미터 수정 - components/header.html: 언어 전환 및 PDF 버튼 추가 - 모든 기능 테스트 완료 및 정상 작동 확인
This commit is contained in:
@@ -35,8 +35,9 @@ window.bookDocumentsApp = () => ({
|
||||
// URL 파라미터 파싱
|
||||
parseUrlParams() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
this.bookId = urlParams.get('bookId');
|
||||
this.bookId = urlParams.get('book_id') || urlParams.get('bookId'); // 둘 다 지원
|
||||
console.log('📖 서적 ID:', this.bookId);
|
||||
console.log('🔍 전체 URL 파라미터:', window.location.search);
|
||||
},
|
||||
|
||||
// 인증 상태 확인
|
||||
@@ -218,6 +219,57 @@ window.bookDocumentsApp = () => ({
|
||||
if (type === 'error') {
|
||||
alert(message);
|
||||
}
|
||||
},
|
||||
|
||||
// PDF를 서적에 연결
|
||||
async matchPDFToBook(pdfId) {
|
||||
if (!this.bookId) {
|
||||
this.showNotification('서적 ID가 없습니다', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm('이 PDF를 현재 서적에 연결하시겠습니까?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('🔗 PDF 매칭 시작:', { pdfId, bookId: this.bookId });
|
||||
|
||||
// PDF 문서를 서적에 연결
|
||||
await window.api.updateDocument(pdfId, {
|
||||
book_id: this.bookId
|
||||
});
|
||||
|
||||
this.showNotification('PDF가 서적에 성공적으로 연결되었습니다');
|
||||
|
||||
// 데이터 새로고침
|
||||
await this.loadBookData();
|
||||
|
||||
} catch (error) {
|
||||
console.error('PDF 매칭 실패:', error);
|
||||
this.showNotification('PDF 연결에 실패했습니다: ' + error.message, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
// PDF 열기
|
||||
openPDF(pdf) {
|
||||
if (pdf.pdf_path) {
|
||||
// PDF 뷰어로 이동
|
||||
window.open(`/viewer.html?id=${pdf.id}`, '_blank');
|
||||
} else {
|
||||
this.showNotification('PDF 파일을 찾을 수 없습니다', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
// 날짜 포맷팅
|
||||
formatDate(dateString) {
|
||||
if (!dateString) return '';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('ko-KR', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -287,8 +287,12 @@ class LinkManager {
|
||||
* 개별 백링크 렌더링
|
||||
*/
|
||||
renderSingleBacklink(backlink) {
|
||||
console.log('🔗 renderSingleBacklink 시작:', backlink.id, backlink.target_text);
|
||||
const content = document.getElementById('document-content');
|
||||
if (!content) return;
|
||||
if (!content) {
|
||||
console.error('❌ document-content 요소를 찾을 수 없습니다');
|
||||
return;
|
||||
}
|
||||
|
||||
// 실제 문서 내용만 추출 (CSS, 스크립트 제외)
|
||||
const contentClone = content.cloneNode(true);
|
||||
|
||||
@@ -800,17 +800,139 @@ window.documentViewer = () => ({
|
||||
// ==================== 언어 전환 ====================
|
||||
toggleLanguage() {
|
||||
this.isKorean = !this.isKorean;
|
||||
const lang = this.isKorean ? 'ko' : 'en';
|
||||
console.log('🌐 언어 전환:', this.isKorean ? '한국어' : 'English');
|
||||
// 언어 전환 로직 구현 필요
|
||||
|
||||
// 문서에 내장된 언어 전환 기능 찾기 및 실행
|
||||
this.findAndExecuteBuiltinLanguageToggle();
|
||||
},
|
||||
|
||||
// 문서에 내장된 언어 전환 기능 찾기
|
||||
findAndExecuteBuiltinLanguageToggle() {
|
||||
console.log('🔍 문서 내장 언어 전환 기능 찾기 시작');
|
||||
|
||||
const content = document.getElementById('document-content');
|
||||
if (!content) {
|
||||
console.warn('❌ document-content 요소를 찾을 수 없습니다');
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 언어 전환 버튼 찾기 (다양한 패턴)
|
||||
const buttonSelectors = [
|
||||
'button[onclick*="toggleLanguage"]',
|
||||
'button[onclick*="language"]',
|
||||
'button[onclick*="Language"]',
|
||||
'.language-toggle',
|
||||
'.lang-toggle',
|
||||
'button[id*="lang"]',
|
||||
'button[class*="lang"]',
|
||||
'input[type="button"][onclick*="language"]'
|
||||
];
|
||||
|
||||
let foundButton = null;
|
||||
for (const selector of buttonSelectors) {
|
||||
const buttons = content.querySelectorAll(selector);
|
||||
if (buttons.length > 0) {
|
||||
foundButton = buttons[0];
|
||||
console.log(`✅ 언어 전환 버튼 발견 (${selector}):`, foundButton.outerHTML.substring(0, 100));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 버튼이 있으면 클릭
|
||||
if (foundButton) {
|
||||
console.log('🔘 내장 언어 전환 버튼 클릭');
|
||||
try {
|
||||
foundButton.click();
|
||||
console.log('✅ 언어 전환 버튼 클릭 완료');
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error('❌ 버튼 클릭 실패:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 버튼이 없으면 스크립트 함수 직접 호출 시도
|
||||
this.tryDirectLanguageFunction();
|
||||
},
|
||||
|
||||
// 직접 언어 전환 함수 호출 시도
|
||||
tryDirectLanguageFunction() {
|
||||
console.log('🔧 직접 언어 전환 함수 호출 시도');
|
||||
|
||||
const functionNames = [
|
||||
'toggleLanguage',
|
||||
'changeLanguage',
|
||||
'switchLanguage',
|
||||
'toggleLang',
|
||||
'changeLang'
|
||||
];
|
||||
|
||||
for (const funcName of functionNames) {
|
||||
if (typeof window[funcName] === 'function') {
|
||||
console.log(`✅ 전역 함수 발견: ${funcName}`);
|
||||
try {
|
||||
window[funcName]();
|
||||
console.log(`✅ ${funcName}() 호출 완료`);
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error(`❌ ${funcName}() 호출 실패:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 문서 내 스크립트에서 함수 찾기
|
||||
this.findLanguageFunctionInScripts();
|
||||
},
|
||||
|
||||
// 문서 내 스크립트에서 언어 전환 함수 찾기
|
||||
findLanguageFunctionInScripts() {
|
||||
console.log('📜 문서 내 스크립트에서 언어 함수 찾기');
|
||||
|
||||
const content = document.getElementById('document-content');
|
||||
const scripts = content.querySelectorAll('script');
|
||||
|
||||
console.log(`📜 발견된 스크립트 태그: ${scripts.length}개`);
|
||||
|
||||
scripts.forEach((script, index) => {
|
||||
const scriptContent = script.textContent || script.innerHTML;
|
||||
if (scriptContent.includes('language') || scriptContent.includes('Language') || scriptContent.includes('lang')) {
|
||||
console.log(`📜 스크립트 ${index + 1}에서 언어 관련 코드 발견:`, scriptContent.substring(0, 200));
|
||||
|
||||
// 함수 실행 시도
|
||||
try {
|
||||
eval(scriptContent);
|
||||
console.log(`✅ 스크립트 ${index + 1} 실행 완료`);
|
||||
} catch (error) {
|
||||
console.log(`⚠️ 스크립트 ${index + 1} 실행 실패:`, error.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('⚠️ 내장 언어 전환 기능을 찾을 수 없습니다');
|
||||
},
|
||||
|
||||
|
||||
|
||||
async downloadOriginalFile() {
|
||||
if (!this.document || !this.document.id) {
|
||||
console.warn('문서 정보가 없습니다');
|
||||
return;
|
||||
}
|
||||
|
||||
// 연결된 PDF가 있는지 확인
|
||||
console.log('📕 PDF 다운로드 시도:', {
|
||||
id: this.document.id,
|
||||
matched_pdf_id: this.document.matched_pdf_id,
|
||||
pdf_path: this.document.pdf_path
|
||||
});
|
||||
|
||||
// 1. 현재 문서 자체가 PDF인 경우
|
||||
if (this.document.pdf_path) {
|
||||
console.log('📄 현재 문서가 PDF - 직접 다운로드');
|
||||
this.downloadPdfFile(this.document.pdf_path, this.document.title || 'document');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 연결된 PDF가 있는지 확인
|
||||
if (!this.document.matched_pdf_id) {
|
||||
alert('연결된 원본 PDF 파일이 없습니다.\n\n서적 편집 페이지에서 PDF 파일을 연결해주세요.');
|
||||
return;
|
||||
@@ -864,6 +986,39 @@ window.documentViewer = () => ({
|
||||
}
|
||||
},
|
||||
|
||||
// PDF 파일 직접 다운로드
|
||||
downloadPdfFile(pdfPath, filename) {
|
||||
try {
|
||||
console.log('📄 PDF 파일 직접 다운로드:', pdfPath);
|
||||
|
||||
// PDF 파일 URL 생성 (상대 경로를 절대 경로로 변환)
|
||||
let pdfUrl = pdfPath;
|
||||
if (!pdfUrl.startsWith('http')) {
|
||||
// 상대 경로인 경우 현재 도메인 기준으로 절대 경로 생성
|
||||
const baseUrl = window.location.origin;
|
||||
pdfUrl = pdfUrl.startsWith('/') ? baseUrl + pdfUrl : baseUrl + '/' + pdfUrl;
|
||||
}
|
||||
|
||||
console.log('📄 PDF URL:', pdfUrl);
|
||||
|
||||
// 다운로드 링크 생성 및 클릭
|
||||
const link = document.createElement('a');
|
||||
link.href = pdfUrl;
|
||||
link.download = filename.endsWith('.pdf') ? filename : filename + '.pdf';
|
||||
link.target = '_blank'; // 새 탭에서 열기 (다운로드 실패 시 뷰어로 열림)
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
console.log('✅ PDF 다운로드 링크 클릭 완료');
|
||||
|
||||
} catch (error) {
|
||||
console.error('PDF 다운로드 오류:', error);
|
||||
alert('PDF 다운로드 중 오류가 발생했습니다: ' + error.message);
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 유틸리티 메서드 ====================
|
||||
formatDate(dateString) {
|
||||
return new Date(dateString).toLocaleString('ko-KR');
|
||||
@@ -1027,6 +1182,30 @@ window.documentViewer = () => ({
|
||||
alert('링크 생성에 실패했습니다: ' + error.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 네비게이션 함수들
|
||||
goBack() {
|
||||
console.log('🔙 뒤로가기');
|
||||
window.history.back();
|
||||
},
|
||||
|
||||
navigateToDocument(documentId) {
|
||||
if (!documentId) {
|
||||
console.warn('⚠️ 문서 ID가 없습니다');
|
||||
return;
|
||||
}
|
||||
console.log('📄 문서로 이동:', documentId);
|
||||
window.location.href = `/viewer.html?id=${documentId}`;
|
||||
},
|
||||
|
||||
goToBookContents() {
|
||||
if (!this.navigation?.book_info?.id) {
|
||||
console.warn('⚠️ 서적 정보가 없습니다');
|
||||
return;
|
||||
}
|
||||
console.log('📚 서적 목차로 이동:', this.navigation.book_info.id);
|
||||
window.location.href = `/book-documents.html?book_id=${this.navigation.book_info.id}`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user