Initial commit: 교육 프로젝트 배포
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
(function () {
|
||||
const learningBridgeState = {
|
||||
initialized: false,
|
||||
config: null,
|
||||
markerManager: null,
|
||||
modal: null,
|
||||
};
|
||||
|
||||
function getLearningConfig() {
|
||||
if (typeof LEARNING_CONFIG !== 'undefined') {
|
||||
return LEARNING_CONFIG;
|
||||
}
|
||||
if (typeof window.LEARNING_CONFIG !== 'undefined') {
|
||||
return window.LEARNING_CONFIG;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getMarkerManagerClass() {
|
||||
if (typeof MarkerManager !== 'undefined') {
|
||||
return MarkerManager;
|
||||
}
|
||||
if (typeof window.MarkerManager !== 'undefined') {
|
||||
return window.MarkerManager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getVideoModalClass() {
|
||||
if (typeof VideoModal !== 'undefined') {
|
||||
return VideoModal;
|
||||
}
|
||||
if (typeof window.VideoModal !== 'undefined') {
|
||||
return window.VideoModal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function ensureDependencies() {
|
||||
if (!getLearningConfig()) {
|
||||
throw new Error('LEARNING_CONFIG is not loaded');
|
||||
}
|
||||
if (!getMarkerManagerClass()) {
|
||||
throw new Error('MarkerManager is not loaded');
|
||||
}
|
||||
if (!getVideoModalClass()) {
|
||||
throw new Error('VideoModal is not loaded');
|
||||
}
|
||||
}
|
||||
|
||||
function ensureHiddenLearningBridgeContainer() {
|
||||
let markersContainer = document.getElementById('markers-container');
|
||||
if (!markersContainer) {
|
||||
markersContainer = document.createElement('div');
|
||||
markersContainer.id = 'markers-container';
|
||||
markersContainer.style.display = 'none';
|
||||
document.body.appendChild(markersContainer);
|
||||
}
|
||||
return markersContainer;
|
||||
}
|
||||
|
||||
function createLearningGaugeStub() {
|
||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
svg.setAttribute('id', 'gauge-svg-search-result-bridge');
|
||||
return {
|
||||
gaugeSvg: svg,
|
||||
isMobile: false,
|
||||
};
|
||||
}
|
||||
|
||||
function buildLearningBridgeChapters(apiChapters) {
|
||||
const learningConfig = getLearningConfig();
|
||||
const templateChapters = Array.isArray(learningConfig?.chapters)
|
||||
? learningConfig.chapters
|
||||
: [];
|
||||
const templateByCode = new Map();
|
||||
|
||||
templateChapters.forEach(function (chapter, index) {
|
||||
const code = String(chapter?.code || `__index_${index}`);
|
||||
templateByCode.set(code, chapter || {});
|
||||
});
|
||||
|
||||
return (Array.isArray(apiChapters) ? apiChapters : []).map(function (apiChapter, chapterIndex) {
|
||||
const templateChapter = templateByCode.get(String(apiChapter?.code || '')) || templateChapters[chapterIndex] || {};
|
||||
const templateLessons = Array.isArray(templateChapter.lessons) ? templateChapter.lessons : [];
|
||||
const lessons = (Array.isArray(apiChapter?.lessons) ? apiChapter.lessons : []).map(function (apiLesson, lessonIndex) {
|
||||
const templateLesson = templateLessons[lessonIndex] || {};
|
||||
const label = String(
|
||||
apiLesson?.title ||
|
||||
templateLesson.label ||
|
||||
`${apiChapter?.name || templateChapter.name || '법정교육'} ${lessonIndex + 1}`
|
||||
);
|
||||
|
||||
return {
|
||||
...templateLesson,
|
||||
type: 'normal',
|
||||
label: label,
|
||||
title: label,
|
||||
url: String(apiLesson?.url || templateLesson.url || ''),
|
||||
content_id: String(apiLesson?.content_id || ''),
|
||||
watch_tm: Number(apiLesson?.watch_tm || 0),
|
||||
content_tm: Number(apiLesson?.content_tm || 0),
|
||||
all_tm: Number(apiLesson?.all_tm || 0),
|
||||
description: String(apiLesson?.description || templateLesson.description || ''),
|
||||
completed: !!apiLesson?.completed,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...templateChapter,
|
||||
id: Number(templateChapter.id || (chapterIndex + 1)),
|
||||
code: String(apiChapter?.code || templateChapter.code || ''),
|
||||
name: String(apiChapter?.name || templateChapter.name || `챕터 ${chapterIndex + 1}`),
|
||||
type: 'chapter',
|
||||
url: String(lessons[0]?.url || templateChapter.url || ''),
|
||||
completed: lessons.length > 0 && lessons.every(function (lesson) { return lesson.completed === true; }),
|
||||
lessons: lessons,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function hydrateLearningBridge() {
|
||||
ensureDependencies();
|
||||
const learningConfig = getLearningConfig();
|
||||
const MarkerManagerClass = getMarkerManagerClass();
|
||||
const VideoModalClass = getVideoModalClass();
|
||||
|
||||
const response = await fetch('/bbs/api/get_learning_chapters.php', {
|
||||
credentials: 'same-origin',
|
||||
});
|
||||
const payload = await response.json();
|
||||
|
||||
if (!response.ok || !payload || payload.success !== true || !Array.isArray(payload.chapters)) {
|
||||
throw new Error(payload?.message || 'failed_to_load_learning_chapters');
|
||||
}
|
||||
|
||||
const bridgeChapters = buildLearningBridgeChapters(payload.chapters);
|
||||
const bridgeConfig = {
|
||||
...learningConfig,
|
||||
chapters: bridgeChapters,
|
||||
settings: {
|
||||
...(learningConfig.settings || {}),
|
||||
},
|
||||
};
|
||||
|
||||
if (!learningBridgeState.initialized) {
|
||||
ensureHiddenLearningBridgeContainer();
|
||||
learningBridgeState.config = bridgeConfig;
|
||||
learningBridgeState.markerManager = new MarkerManagerClass(createLearningGaugeStub(), bridgeConfig);
|
||||
learningBridgeState.modal = new VideoModalClass(bridgeConfig, learningBridgeState.markerManager);
|
||||
|
||||
if (typeof learningBridgeState.markerManager.setModalInstance === 'function') {
|
||||
learningBridgeState.markerManager.setModalInstance(learningBridgeState.modal);
|
||||
}
|
||||
|
||||
learningBridgeState.initialized = true;
|
||||
} else {
|
||||
learningBridgeState.config = bridgeConfig;
|
||||
learningBridgeState.markerManager.config = bridgeConfig;
|
||||
learningBridgeState.markerManager.allMarkers = bridgeConfig.getAllMarkers();
|
||||
learningBridgeState.modal.config = bridgeConfig;
|
||||
learningBridgeState.modal.markerManager = learningBridgeState.markerManager;
|
||||
}
|
||||
|
||||
return learningBridgeState;
|
||||
}
|
||||
|
||||
window._learningOpenModal = async function (info) {
|
||||
const bridge = await hydrateLearningBridge();
|
||||
const contentId = String(info?.contentId || '');
|
||||
const allMarkers = typeof bridge.config?.getAllMarkers === 'function'
|
||||
? bridge.config.getAllMarkers()
|
||||
: bridge.markerManager.allMarkers;
|
||||
|
||||
const globalIndex = allMarkers.findIndex(function (marker) {
|
||||
return marker && marker.isChapterMarker !== true && String(marker.content_id || '') === contentId;
|
||||
});
|
||||
|
||||
if (globalIndex < 0) {
|
||||
throw new Error(`learning lesson not found: ${contentId}`);
|
||||
}
|
||||
|
||||
bridge.markerManager.allMarkers = allMarkers;
|
||||
const lessonData = allMarkers[globalIndex];
|
||||
await bridge.modal.load(lessonData, globalIndex);
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,106 @@
|
||||
(function () {
|
||||
const onboardingBridgeState = {
|
||||
chapters: null,
|
||||
pending: null,
|
||||
};
|
||||
|
||||
function getPuzzleModalManagerClass() {
|
||||
if (typeof PuzzleModalManager !== 'undefined') {
|
||||
return PuzzleModalManager;
|
||||
}
|
||||
if (typeof window.PuzzleModalManager !== 'undefined') {
|
||||
return window.PuzzleModalManager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function ensureDependencies() {
|
||||
if (!getPuzzleModalManagerClass()) {
|
||||
throw new Error('PuzzleModalManager is not loaded');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadOnboardingChapters() {
|
||||
if (Array.isArray(onboardingBridgeState.chapters)) {
|
||||
return onboardingBridgeState.chapters;
|
||||
}
|
||||
|
||||
if (onboardingBridgeState.pending) {
|
||||
return onboardingBridgeState.pending;
|
||||
}
|
||||
|
||||
onboardingBridgeState.pending = fetch('/bbs/api/get_onboarding_chapters.php', {
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(async function (response) {
|
||||
const payload = await response.json();
|
||||
if (!response.ok || !payload || payload.success !== true || !Array.isArray(payload.chapters)) {
|
||||
throw new Error(payload?.message || 'failed_to_load_onboarding_chapters');
|
||||
}
|
||||
|
||||
onboardingBridgeState.chapters = payload.chapters;
|
||||
window.puzzleChapterData = payload.chapters;
|
||||
return payload.chapters;
|
||||
})
|
||||
.finally(function () {
|
||||
onboardingBridgeState.pending = null;
|
||||
});
|
||||
|
||||
return onboardingBridgeState.pending;
|
||||
}
|
||||
|
||||
function cloneChapter(chapter) {
|
||||
return JSON.parse(JSON.stringify(chapter || {}));
|
||||
}
|
||||
|
||||
function findChapterIndexByContentId(chapters, contentId) {
|
||||
const id = String(contentId || '');
|
||||
if (id === '') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return chapters.findIndex(function (chapter) {
|
||||
const lessons = Array.isArray(chapter?.lessons) ? chapter.lessons : [];
|
||||
return lessons.some(function (lesson) {
|
||||
return String(lesson?.content_id || '') === id;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function applyBridgeOverrides(chapter, info) {
|
||||
const contentId = String(info?.contentId || '');
|
||||
if (!contentId || !Array.isArray(chapter?.lessons)) {
|
||||
return chapter;
|
||||
}
|
||||
|
||||
chapter.lessons = chapter.lessons.map(function (lesson) {
|
||||
if (String(lesson?.content_id || '') !== contentId) {
|
||||
return lesson;
|
||||
}
|
||||
|
||||
return {
|
||||
...lesson,
|
||||
watch_tm: Math.max(Number(lesson?.watch_tm || 0), Number(info?.watchTm || 0)),
|
||||
content_tm: Math.max(Number(lesson?.content_tm || 0), Number(info?.contentTm || 0)),
|
||||
is_bookmarked: info?.bookmark === true ? true : lesson?.is_bookmarked === true,
|
||||
};
|
||||
});
|
||||
|
||||
return chapter;
|
||||
}
|
||||
|
||||
window._onboardingOpenModal = async function (info) {
|
||||
ensureDependencies();
|
||||
|
||||
const PuzzleModalManagerClass = getPuzzleModalManagerClass();
|
||||
const chapters = await loadOnboardingChapters();
|
||||
const chapterIndex = findChapterIndexByContentId(chapters, info?.contentId);
|
||||
|
||||
if (chapterIndex < 0) {
|
||||
throw new Error('onboarding chapter not found');
|
||||
}
|
||||
|
||||
const chapter = applyBridgeOverrides(cloneChapter(chapters[chapterIndex]), info);
|
||||
await PuzzleModalManagerClass.openChapterModal(chapterIndex, chapter);
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user