하이라이트 색상 문제 해결 및 다중 하이라이트 렌더링 개선
주요 수정사항: - 하이라이트 생성 시 color → highlight_color 필드명 수정으로 색상 전달 문제 해결 - 분홍색을 더 연하게 변경하여 글씨 가독성 향상 - 다중 하이라이트 렌더링을 위아래 균등 분할로 개선 - CSS highlight-span 클래스 추가 및 색상 적용 강화 - 하이라이트 생성/렌더링 과정에 상세한 디버깅 로그 추가 UI 개선: - 단일 하이라이트: 선택한 색상으로 정확히 표시 - 다중 하이라이트: 위아래로 균등하게 색상 분할 표시 - 메모 입력 모달에서 선택된 텍스트 표시 개선 버그 수정: - 프론트엔드-백엔드 API 스키마 불일치 해결 - CSS 스타일 우선순위 문제 해결 - 하이라이트 색상이 노랑색으로만 표시되던 문제 해결
This commit is contained in:
223
frontend/static/js/viewer/utils/module-loader.js
Normal file
223
frontend/static/js/viewer/utils/module-loader.js
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* ModuleLoader - 지연 로딩 및 모듈 관리
|
||||
* 필요한 모듈만 동적으로 로드하여 성능을 최적화합니다.
|
||||
*/
|
||||
class ModuleLoader {
|
||||
constructor() {
|
||||
console.log('🔧 ModuleLoader 초기화 시작');
|
||||
|
||||
// 로드된 모듈 캐시
|
||||
this.loadedModules = new Map();
|
||||
|
||||
// 로딩 중인 모듈 Promise 캐시 (중복 로딩 방지)
|
||||
this.loadingPromises = new Map();
|
||||
|
||||
// 모듈 의존성 정의
|
||||
this.moduleDependencies = {
|
||||
'DocumentLoader': [],
|
||||
'HighlightManager': ['DocumentLoader'],
|
||||
'BookmarkManager': ['DocumentLoader'],
|
||||
'LinkManager': ['DocumentLoader'],
|
||||
'UIManager': []
|
||||
};
|
||||
|
||||
// 모듈 경로 정의
|
||||
this.modulePaths = {
|
||||
'DocumentLoader': '/static/js/viewer/core/document-loader.js',
|
||||
'HighlightManager': '/static/js/viewer/features/highlight-manager.js',
|
||||
'BookmarkManager': '/static/js/viewer/features/bookmark-manager.js',
|
||||
'LinkManager': '/static/js/viewer/features/link-manager.js',
|
||||
'UIManager': '/static/js/viewer/features/ui-manager.js'
|
||||
};
|
||||
|
||||
// 캐시 버스팅을 위한 버전
|
||||
this.version = '2025012607';
|
||||
|
||||
console.log('✅ ModuleLoader 초기화 완료');
|
||||
}
|
||||
|
||||
/**
|
||||
* 모듈 동적 로드
|
||||
*/
|
||||
async loadModule(moduleName) {
|
||||
// 이미 로드된 모듈인지 확인
|
||||
if (this.loadedModules.has(moduleName)) {
|
||||
console.log(`✅ 모듈 캐시에서 반환: ${moduleName}`);
|
||||
return this.loadedModules.get(moduleName);
|
||||
}
|
||||
|
||||
// 이미 로딩 중인 모듈인지 확인 (중복 로딩 방지)
|
||||
if (this.loadingPromises.has(moduleName)) {
|
||||
console.log(`⏳ 모듈 로딩 대기 중: ${moduleName}`);
|
||||
return await this.loadingPromises.get(moduleName);
|
||||
}
|
||||
|
||||
console.log(`🔄 모듈 로딩 시작: ${moduleName}`);
|
||||
|
||||
// 로딩 Promise 생성 및 캐시
|
||||
const loadingPromise = this._loadModuleScript(moduleName);
|
||||
this.loadingPromises.set(moduleName, loadingPromise);
|
||||
|
||||
try {
|
||||
const moduleClass = await loadingPromise;
|
||||
|
||||
// 로딩 완료 후 캐시에 저장
|
||||
this.loadedModules.set(moduleName, moduleClass);
|
||||
this.loadingPromises.delete(moduleName);
|
||||
|
||||
console.log(`✅ 모듈 로딩 완료: ${moduleName}`);
|
||||
return moduleClass;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ 모듈 로딩 실패: ${moduleName}`, error);
|
||||
this.loadingPromises.delete(moduleName);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 의존성을 포함한 모듈 로드
|
||||
*/
|
||||
async loadModuleWithDependencies(moduleName) {
|
||||
console.log(`🔗 의존성 포함 모듈 로딩: ${moduleName}`);
|
||||
|
||||
// 의존성 먼저 로드
|
||||
const dependencies = this.moduleDependencies[moduleName] || [];
|
||||
if (dependencies.length > 0) {
|
||||
console.log(`📦 의존성 로딩: ${dependencies.join(', ')}`);
|
||||
await Promise.all(dependencies.map(dep => this.loadModule(dep)));
|
||||
}
|
||||
|
||||
// 메인 모듈 로드
|
||||
return await this.loadModule(moduleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 여러 모듈 병렬 로드
|
||||
*/
|
||||
async loadModules(moduleNames) {
|
||||
console.log(`🚀 병렬 모듈 로딩: ${moduleNames.join(', ')}`);
|
||||
|
||||
const loadPromises = moduleNames.map(name => this.loadModuleWithDependencies(name));
|
||||
const results = await Promise.all(loadPromises);
|
||||
|
||||
console.log(`✅ 병렬 모듈 로딩 완료: ${moduleNames.join(', ')}`);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 스크립트 동적 로딩
|
||||
*/
|
||||
async _loadModuleScript(moduleName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 이미 전역에 클래스가 있는지 확인
|
||||
if (window[moduleName]) {
|
||||
console.log(`✅ 모듈 이미 로드됨: ${moduleName}`);
|
||||
resolve(window[moduleName]);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`📥 스크립트 로딩 시작: ${moduleName}`);
|
||||
const script = document.createElement('script');
|
||||
script.src = `${this.modulePaths[moduleName]}?v=${this.version}`;
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
console.log(`📥 스크립트 로드 완료: ${moduleName}`);
|
||||
|
||||
// 스크립트 로드 후 잠시 대기 (클래스 등록 시간)
|
||||
setTimeout(() => {
|
||||
if (window[moduleName]) {
|
||||
console.log(`✅ 모듈 클래스 확인: ${moduleName}`);
|
||||
resolve(window[moduleName]);
|
||||
} else {
|
||||
console.error(`❌ 모듈 클래스 없음: ${moduleName}`, Object.keys(window).filter(k => k.includes('Manager') || k.includes('Loader')));
|
||||
reject(new Error(`모듈 클래스를 찾을 수 없음: ${moduleName}`));
|
||||
}
|
||||
}, 10); // 10ms 대기
|
||||
};
|
||||
|
||||
script.onerror = (error) => {
|
||||
console.error(`❌ 스크립트 로딩 실패: ${moduleName}`, error);
|
||||
reject(new Error(`스크립트 로딩 실패: ${moduleName}`));
|
||||
};
|
||||
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 모듈 인스턴스 생성 (팩토리 패턴)
|
||||
*/
|
||||
async createModuleInstance(moduleName, ...args) {
|
||||
const ModuleClass = await this.loadModuleWithDependencies(moduleName);
|
||||
return new ModuleClass(...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 모듈 프리로딩 (백그라운드에서 미리 로드)
|
||||
*/
|
||||
async preloadModules(moduleNames) {
|
||||
console.log(`🔮 모듈 프리로딩: ${moduleNames.join(', ')}`);
|
||||
|
||||
// 백그라운드에서 로드 (에러 무시)
|
||||
const preloadPromises = moduleNames.map(async (name) => {
|
||||
try {
|
||||
await this.loadModuleWithDependencies(name);
|
||||
console.log(`✅ 프리로딩 완료: ${name}`);
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ 프리로딩 실패: ${name}`, error);
|
||||
}
|
||||
});
|
||||
|
||||
// 모든 프리로딩이 완료될 때까지 기다리지 않음
|
||||
Promise.all(preloadPromises);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용하지 않는 모듈 언로드 (메모리 최적화)
|
||||
*/
|
||||
unloadModule(moduleName) {
|
||||
if (this.loadedModules.has(moduleName)) {
|
||||
this.loadedModules.delete(moduleName);
|
||||
console.log(`🗑️ 모듈 언로드: ${moduleName}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 모듈 언로드
|
||||
*/
|
||||
unloadAllModules() {
|
||||
this.loadedModules.clear();
|
||||
this.loadingPromises.clear();
|
||||
console.log('🗑️ 모든 모듈 언로드 완료');
|
||||
}
|
||||
|
||||
/**
|
||||
* 로드된 모듈 상태 확인
|
||||
*/
|
||||
getLoadedModules() {
|
||||
return Array.from(this.loadedModules.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 메모리 사용량 추정
|
||||
*/
|
||||
getMemoryUsage() {
|
||||
const loadedCount = this.loadedModules.size;
|
||||
const loadingCount = this.loadingPromises.size;
|
||||
|
||||
return {
|
||||
loadedModules: loadedCount,
|
||||
loadingModules: loadingCount,
|
||||
totalModules: Object.keys(this.modulePaths).length,
|
||||
memoryEstimate: `${loadedCount * 50}KB` // 대략적인 추정
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 전역 모듈 로더 인스턴스
|
||||
window.moduleLoader = new ModuleLoader();
|
||||
|
||||
// 전역으로 내보내기
|
||||
window.ModuleLoader = ModuleLoader;
|
||||
Reference in New Issue
Block a user