Initial commit: 교육 프로젝트 배포
This commit is contained in:
+580
@@ -0,0 +1,580 @@
|
||||
/**
|
||||
* 마이클래스 페이지 전용 스크립트
|
||||
* - Lottie 아이콘, 순위/연도 토글, 목표 선택 팝업(Swiper)
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// ====================================================
|
||||
// [1] Lottie 아이콘 초기화 (.lottie-icon)
|
||||
// - 목표 카드/팝업 아이콘 애니메이션, prefers-reduced-motion 시 비활성
|
||||
// ====================================================
|
||||
const initLottieIconsIn = (function initLottieIcons() {
|
||||
function loadLottieScript() {
|
||||
if (typeof window.lottie !== 'undefined') return Promise.resolve(true);
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
const existing = document.querySelector('script[data-lottie-loader="true"]');
|
||||
if (existing) {
|
||||
existing.addEventListener('load', function () { resolve(typeof window.lottie !== 'undefined'); });
|
||||
existing.addEventListener('error', function () { resolve(false); });
|
||||
return;
|
||||
}
|
||||
|
||||
const s = document.createElement('script');
|
||||
s.src = './assets/js/lib/lottie.min.js';
|
||||
s.async = true;
|
||||
s.dataset.lottieLoader = 'true';
|
||||
s.addEventListener('load', function () { resolve(typeof window.lottie !== 'undefined'); });
|
||||
s.addEventListener('error', function () { resolve(false); });
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
}
|
||||
|
||||
const reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
function initOne(el) {
|
||||
const url = el.getAttribute('data-lottie-url');
|
||||
if (!url) return;
|
||||
if (el.dataset.lottieInited === 'true') return;
|
||||
|
||||
const fallbackImg = el.parentElement ? el.parentElement.querySelector('.lottie-fallback') : null;
|
||||
|
||||
el.dataset.lottieInited = 'true';
|
||||
|
||||
try {
|
||||
if (el.__lottieAnim && typeof el.__lottieAnim.destroy === 'function') {
|
||||
el.__lottieAnim.destroy();
|
||||
el.__lottieAnim = null;
|
||||
}
|
||||
const anim = window.lottie.loadAnimation({
|
||||
container: el,
|
||||
renderer: 'svg',
|
||||
loop: !reduceMotion,
|
||||
autoplay: !reduceMotion,
|
||||
path: url,
|
||||
rendererSettings: { progressiveLoad: true },
|
||||
});
|
||||
el.__lottieAnim = anim;
|
||||
|
||||
if (fallbackImg) fallbackImg.style.display = 'none';
|
||||
|
||||
anim.addEventListener('data_failed', function () {
|
||||
el.dataset.lottieInited = 'false';
|
||||
if (fallbackImg) fallbackImg.style.display = '';
|
||||
});
|
||||
} catch (e) {
|
||||
el.dataset.lottieInited = 'false';
|
||||
if (fallbackImg) fallbackImg.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
function initIn(rootEl, options) {
|
||||
var root = rootEl && rootEl.querySelectorAll ? rootEl : document;
|
||||
var opts = options || {};
|
||||
var force = !!opts.force;
|
||||
var scopedIcons = root.querySelectorAll('.lottie-icon[data-lottie-url]');
|
||||
|
||||
if (force) {
|
||||
scopedIcons.forEach(function (el) {
|
||||
el.dataset.lottieInited = 'false';
|
||||
el.innerHTML = '';
|
||||
});
|
||||
}
|
||||
|
||||
return loadLottieScript().then(function (ok) {
|
||||
if (!ok || typeof window.lottie === 'undefined') return;
|
||||
scopedIcons.forEach(initOne);
|
||||
});
|
||||
}
|
||||
|
||||
initIn(document);
|
||||
return initIn;
|
||||
})();
|
||||
|
||||
// ====================================================
|
||||
// [2] 순위 목록 토글
|
||||
// - 상단 트로피 버튼 클릭 시 1~5위 팝업 열기/닫기, 바깥 클릭 시 닫기
|
||||
// ====================================================
|
||||
const btnRankToggle = document.querySelector('.btn-rank-toggle');
|
||||
const rankListPopup = document.getElementById('rankListPopup');
|
||||
|
||||
if (btnRankToggle && rankListPopup) {
|
||||
btnRankToggle.addEventListener('click', function () {
|
||||
const isOpen = this.classList.toggle('is-open');
|
||||
rankListPopup.hidden = !isOpen;
|
||||
this.setAttribute('aria-expanded', isOpen);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
if (btnRankToggle.classList.contains('is-open') &&
|
||||
!btnRankToggle.contains(e.target) &&
|
||||
!rankListPopup.contains(e.target)) {
|
||||
btnRankToggle.classList.remove('is-open');
|
||||
rankListPopup.hidden = true;
|
||||
btnRankToggle.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// [3] 연도 선택 셀렉트
|
||||
// - 연도 버튼 클릭 시 연도 목록 팝업, 선택 시 .year-display 갱신
|
||||
// ====================================================
|
||||
const btnYearToggle = document.getElementById('btnYearToggle');
|
||||
const yearListPopup = document.getElementById('yearListPopup');
|
||||
const yearDisplay = document.querySelector('.year-display');
|
||||
const yearDisplayStrong = yearDisplay?.querySelector('strong');
|
||||
|
||||
function setYearDisplay(year) {
|
||||
if (!yearDisplay || !yearDisplayStrong) return;
|
||||
const prefix = String(year).slice(0, -2);
|
||||
const suffix = String(year).slice(-2);
|
||||
const textNode = Array.from(yearDisplay.childNodes).find(function (n) { return n.nodeType === Node.TEXT_NODE; });
|
||||
if (textNode) {
|
||||
textNode.textContent = prefix;
|
||||
} else {
|
||||
yearDisplay.insertBefore(document.createTextNode(prefix), yearDisplayStrong);
|
||||
}
|
||||
yearDisplayStrong.textContent = suffix;
|
||||
}
|
||||
|
||||
function closeYearSelect() {
|
||||
if (btnYearToggle) {
|
||||
btnYearToggle.classList.remove('is-open');
|
||||
btnYearToggle.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
if (yearListPopup) yearListPopup.hidden = true;
|
||||
}
|
||||
|
||||
if (btnYearToggle && yearListPopup && yearDisplay) {
|
||||
btnYearToggle.addEventListener('click', function () {
|
||||
const isOpen = this.classList.toggle('is-open');
|
||||
yearListPopup.hidden = !isOpen;
|
||||
this.setAttribute('aria-expanded', isOpen);
|
||||
});
|
||||
|
||||
yearListPopup.querySelectorAll('.year-option').forEach(function (opt) {
|
||||
opt.addEventListener('click', function () {
|
||||
const year = this.dataset.year;
|
||||
setYearDisplay(year);
|
||||
closeYearSelect();
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
if (btnYearToggle.classList.contains('is-open') &&
|
||||
!btnYearToggle.contains(e.target) &&
|
||||
!yearListPopup.contains(e.target)) {
|
||||
closeYearSelect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// [4] 목표 데이터 (HTML의 window.MYCLASS_GOALS에서 로드)
|
||||
// - id, title, desc; goalCardColors는 슬라이드 카드 배경색
|
||||
// ====================================================
|
||||
const goals = (window.MYCLASS_GOALS && Array.isArray(window.MYCLASS_GOALS)) ? window.MYCLASS_GOALS : [];
|
||||
const goalRecs = (window.MYCLASS_GOAL_RECS && typeof window.MYCLASS_GOAL_RECS === 'object') ? window.MYCLASS_GOAL_RECS : {};
|
||||
const goalBooks = (window.MYCLASS_GOAL_BOOKS && typeof window.MYCLASS_GOAL_BOOKS === 'object') ? window.MYCLASS_GOAL_BOOKS : {};
|
||||
const goalCodeMap = (window.MYCLASS_GOAL_CODE_MAP && typeof window.MYCLASS_GOAL_CODE_MAP === 'object') ? window.MYCLASS_GOAL_CODE_MAP : {};
|
||||
const quarterCode = (typeof window.MYCLASS_QUARTER_CODE === 'string') ? window.MYCLASS_QUARTER_CODE : '';
|
||||
|
||||
let currentGoalId = null;
|
||||
let selectedGoalId = null;
|
||||
|
||||
const goalLayer = document.getElementById('goalLayer');
|
||||
const btnCloseLayer = document.getElementById('btnCloseLayer');
|
||||
const btnSetGoal = document.getElementById('btnSetGoal');
|
||||
const btnSelectGoal = document.getElementById('btnSelectGoal');
|
||||
const goalSlideWrapper = document.getElementById('goalSlideWrapper');
|
||||
const popupPagination = document.getElementById('popupPagination');
|
||||
|
||||
let goalPopupSwiper = null;
|
||||
|
||||
// 목표별 카드 배경색 (팝업 내 비활성 슬라이드 카드용)
|
||||
const goalCardColors = {
|
||||
1: '#46B8A5', 2: '#3EAEBC', 3: '#46B8A5', 4: '#3B9EAC',
|
||||
5: '#3EB09C', 6: '#42ACBA', 7: '#3DAE9E', 8: '#40B2A2',
|
||||
};
|
||||
|
||||
function escapeHtml(text) {
|
||||
return String(text || '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function formatMultilineHtml(text) {
|
||||
return escapeHtml(String(text || '').replace(/\\n/g, '\n')).replace(/\r?\n/g, '<br>');
|
||||
}
|
||||
|
||||
function populateGoalSlideBooks(slide, goalId) {
|
||||
const list = slide.querySelector('.goal-slide-bookshelf .books-list');
|
||||
if (!list) return;
|
||||
|
||||
const firstCard = list.querySelector('.books-item');
|
||||
if (!firstCard) return;
|
||||
|
||||
const template = firstCard.cloneNode(true);
|
||||
const books = goalBooks[String(goalId)] || goalBooks[goalId] || [];
|
||||
const renderBooks = Array.isArray(books) && books.length ? books : [];
|
||||
|
||||
list.innerHTML = '';
|
||||
|
||||
if (!renderBooks.length) {
|
||||
list.appendChild(template);
|
||||
return;
|
||||
}
|
||||
|
||||
renderBooks.forEach(function (book, index) {
|
||||
const item = template.cloneNode(true);
|
||||
const contentId = parseInt(book.id, 10);
|
||||
const videoId = Number.isNaN(contentId) ? (index + 1) : contentId;
|
||||
const title = String(book.title || '');
|
||||
const sub = String(book.sub || '');
|
||||
const main = String(book.main || '');
|
||||
const youtube = String(book.youtube || '');
|
||||
const thumb = String(book.thumbnail || '');
|
||||
const fallbackImgName = String(book.img || 'img_book_01');
|
||||
const coverDesktop = thumb || ('/img/myclass/' + fallbackImgName + '.png');
|
||||
const coverMobile = thumb || ('/img/myclass/' + fallbackImgName + '_m.png');
|
||||
const videoThumb = thumb || (youtube ? ('https://img.youtube.com/vi/' + youtube + '/sddefault.jpg') : coverDesktop);
|
||||
|
||||
item.setAttribute('data-video-id', String(videoId));
|
||||
|
||||
const imgWrap = item.querySelector('.book-img-wrap');
|
||||
if (imgWrap) {
|
||||
imgWrap.style.setProperty('--book-img', "url('" + coverDesktop + "')");
|
||||
imgWrap.style.setProperty('--book-img-m', "url('" + coverMobile + "')");
|
||||
}
|
||||
|
||||
const sourceEl = item.querySelector('.book-img-picture source');
|
||||
const imageEl = item.querySelector('.book-img-picture img');
|
||||
if (sourceEl) sourceEl.setAttribute('srcset', coverMobile);
|
||||
if (imageEl) imageEl.setAttribute('src', coverDesktop);
|
||||
|
||||
const infoBtn = item.querySelector('.book-info-btn');
|
||||
if (infoBtn) {
|
||||
infoBtn.setAttribute('data-video-id', String(videoId));
|
||||
infoBtn.setAttribute('aria-label', '영상 상세 보기 - ' + title);
|
||||
}
|
||||
|
||||
const videoThumbEl = item.querySelector('.book-video-thumb');
|
||||
if (videoThumbEl) {
|
||||
videoThumbEl.setAttribute('src', videoThumb);
|
||||
}
|
||||
|
||||
const bookmarkLabel = item.querySelector('.bookmark');
|
||||
const bookmarkInput = bookmarkLabel ? bookmarkLabel.querySelector('input[type="checkbox"]') : null;
|
||||
if (bookmarkLabel && bookmarkInput) {
|
||||
const bookmarkId = 'like_book_goal_' + goalId + '_' + videoId + '_' + index;
|
||||
bookmarkInput.id = bookmarkId;
|
||||
bookmarkLabel.setAttribute('for', bookmarkId);
|
||||
}
|
||||
|
||||
const titleEl = item.querySelector('.book-title');
|
||||
const subEl = item.querySelector('.book-desc-sub');
|
||||
const mainEl = item.querySelector('.book-desc-main');
|
||||
|
||||
if (titleEl) titleEl.textContent = title;
|
||||
if (subEl) subEl.innerHTML = formatMultilineHtml(sub);
|
||||
if (mainEl) mainEl.innerHTML = formatMultilineHtml(main);
|
||||
|
||||
list.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
// 팝업용 슬라이드 DOM 생성 및 목표 데이터 반영
|
||||
function buildGoalSlides() {
|
||||
const templateSlide = goalSlideWrapper && goalSlideWrapper.querySelector('.goal-slide');
|
||||
if (!templateSlide) return;
|
||||
|
||||
for (let i = 1; i < goals.length; i++) {
|
||||
const clone = templateSlide.cloneNode(true);
|
||||
clone.dataset.goalId = goals[i].id;
|
||||
clone.classList.remove('swiper-slide-active', 'swiper-slide-prev', 'swiper-slide-next');
|
||||
goalSlideWrapper.appendChild(clone);
|
||||
}
|
||||
|
||||
goals.forEach(function (goal) {
|
||||
const slide = goalSlideWrapper.querySelector('.goal-slide[data-goal-id="' + goal.id + '"]');
|
||||
const goalItem = document.querySelector('.goal-item[data-goal-id="' + goal.id + '"]');
|
||||
if (!slide) return;
|
||||
|
||||
const color = goalCardColors[goal.id] || '#46B8A5';
|
||||
slide.style.setProperty('--card-color-1', color);
|
||||
|
||||
const titleEl = slide.querySelector('.goal-slide-title');
|
||||
const descEl = slide.querySelector('.goal-slide-desc');
|
||||
const iconEl = slide.querySelector('.goal-slide-icon');
|
||||
if (titleEl) titleEl.textContent = goal.title;
|
||||
if (descEl) descEl.textContent = goal.desc;
|
||||
|
||||
const miniTitleEl = slide.querySelector('.goal-slide-title-mini');
|
||||
const miniDescEl = slide.querySelector('.goal-slide-desc-mini');
|
||||
const miniIconEl = slide.querySelector('.goal-slide-icon-mini');
|
||||
if (miniTitleEl) miniTitleEl.textContent = goal.title;
|
||||
if (miniDescEl) miniDescEl.textContent = goal.desc;
|
||||
|
||||
const recItems = goalRecs[String(goal.id)] || goalRecs[goal.id] || [];
|
||||
const recTitleEls = slide.querySelectorAll('.goal-slide-recs .rec-target');
|
||||
const recTextEls = slide.querySelectorAll('.goal-slide-recs .rec-text');
|
||||
Array.prototype.forEach.call(recTitleEls, function (el, idx) {
|
||||
if (recItems[idx] && recItems[idx].title) {
|
||||
el.textContent = recItems[idx].title;
|
||||
}
|
||||
});
|
||||
Array.prototype.forEach.call(recTextEls, function (el, idx) {
|
||||
if (recItems[idx] && recItems[idx].description) {
|
||||
el.textContent = recItems[idx].description;
|
||||
}
|
||||
});
|
||||
|
||||
populateGoalSlideBooks(slide, goal.id);
|
||||
|
||||
if (goalItem) {
|
||||
const cardIcon = goalItem.querySelector('.card-icon');
|
||||
if (iconEl) iconEl.innerHTML = cardIcon ? cardIcon.innerHTML : '';
|
||||
if (miniIconEl) miniIconEl.innerHTML = cardIcon ? cardIcon.innerHTML : '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 목표 팝업: 활성 슬라이드 폭(100% vs 264px) 반영 후 translate 재정렬 (클릭·스와이프·페이지네이션 공통)
|
||||
function recenterGoalPopupSwiper(swiper, index) {
|
||||
if (!swiper || swiper.destroyed) return;
|
||||
var idx = index !== undefined && index !== null ? index : swiper.activeIndex;
|
||||
requestAnimationFrame(function () {
|
||||
swiper.update();
|
||||
swiper.slideTo(idx, 0, false);
|
||||
});
|
||||
}
|
||||
|
||||
// 목표 팝업 내 Swiper 초기화 (슬라이드 인덱스로 열기)
|
||||
function initGoalPopupSwiper(slideIndex) {
|
||||
if (goalPopupSwiper) return;
|
||||
|
||||
const initialIndex = Math.max(0, Number(slideIndex) || 0);
|
||||
|
||||
goalPopupSwiper = new Swiper('.goal-popup-swiper', {
|
||||
slidesPerView: 'auto',
|
||||
spaceBetween: 16,
|
||||
speed: 0,
|
||||
followFinger: false,
|
||||
observer: true,
|
||||
observeParents: true,
|
||||
slideToClickedSlide: true,
|
||||
grabCursor: true,
|
||||
centeredSlides: true,
|
||||
initialSlide: initialIndex,
|
||||
pagination: {
|
||||
el: '#popupPagination',
|
||||
clickable: true,
|
||||
bulletClass: 'pagination-dot',
|
||||
bulletActiveClass: 'is-active',
|
||||
},
|
||||
on: {
|
||||
slideChange: function () {
|
||||
currentGoalId = goals[this.activeIndex] ? goals[this.activeIndex].id : currentGoalId;
|
||||
},
|
||||
slideChangeTransitionEnd: function () {
|
||||
recenterGoalPopupSwiper(this);
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function destroyGoalPopupSwiper() {
|
||||
if (goalPopupSwiper) {
|
||||
goalPopupSwiper.destroy(true, true);
|
||||
goalPopupSwiper = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 목표 상세 레이어 열기 (goalId에 해당하는 슬라이드로 포커스)
|
||||
function openGoalLayer(goalId) {
|
||||
currentGoalId = goalId;
|
||||
goalLayer.removeAttribute('aria-hidden');
|
||||
goalLayer.classList.remove('hidden');
|
||||
goalLayer.classList.add('is-open');
|
||||
document.body.classList.add('layer-open');
|
||||
buildGoalSlides();
|
||||
const goalIdNum = Number(goalId);
|
||||
const slideIdx = goals.findIndex(function (g) { return g.id === goalIdNum || g.id === goalId; });
|
||||
const safeIndex = slideIdx >= 0 ? slideIdx : 0;
|
||||
const swiperEl = document.querySelector('.goal-popup-swiper');
|
||||
swiperEl.classList.add('swiper-no-anim');
|
||||
initGoalPopupSwiper(safeIndex);
|
||||
requestAnimationFrame(function () {
|
||||
requestAnimationFrame(function () {
|
||||
if (goalPopupSwiper) {
|
||||
recenterGoalPopupSwiper(goalPopupSwiper, safeIndex);
|
||||
}
|
||||
swiperEl.classList.remove('swiper-no-anim');
|
||||
});
|
||||
});
|
||||
initLottieIconsIn(goalLayer, { force: true });
|
||||
if (btnCloseLayer) btnCloseLayer.focus();
|
||||
}
|
||||
|
||||
// 목표 상세 레이어 닫기 (Swiper 제거, 슬라이드 DOM 정리)
|
||||
function closeGoalLayer() {
|
||||
destroyGoalPopupSwiper();
|
||||
if (goalSlideWrapper) {
|
||||
const slides = goalSlideWrapper.querySelectorAll('.goal-slide');
|
||||
slides.forEach(function (s, i) { if (i > 0) s.remove(); });
|
||||
}
|
||||
goalLayer.setAttribute('aria-hidden', 'true');
|
||||
goalLayer.classList.remove('is-open');
|
||||
goalLayer.classList.add('hidden');
|
||||
document.body.classList.remove('layer-open');
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// [5] 목표 설정하기
|
||||
// ====================================================
|
||||
async function saveSelectedGoalToServer(goalId) {
|
||||
const goalCode = goalCodeMap[String(goalId)] || goalCodeMap[goalId] || '';
|
||||
if (!goalCode) {
|
||||
return { ok: false, message: 'goal_code_missing' };
|
||||
}
|
||||
|
||||
const response = await fetch('/bbs/api/save_user_learning_goal.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ goal_code: goalCode, quarter: quarterCode }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
let failedPayload = null;
|
||||
try {
|
||||
failedPayload = await response.json();
|
||||
} catch (_e) {
|
||||
failedPayload = null;
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
message: (failedPayload && failedPayload.message) ? failedPayload.message : ('http_' + response.status),
|
||||
};
|
||||
}
|
||||
|
||||
let payload = null;
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch (_e) {
|
||||
payload = null;
|
||||
}
|
||||
|
||||
return {
|
||||
ok: !!(payload && payload.success),
|
||||
message: (payload && payload.message) ? payload.message : '',
|
||||
};
|
||||
}
|
||||
|
||||
if (btnSetGoal) {
|
||||
btnSetGoal.addEventListener('click', async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const nextUrl = btnSetGoal.getAttribute('href') || '/skin/myclass_list.php';
|
||||
selectedGoalId = currentGoalId;
|
||||
|
||||
if (!selectedGoalId) {
|
||||
window.location.href = nextUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
btnSetGoal.classList.add('is-loading');
|
||||
btnSetGoal.setAttribute('aria-disabled', 'true');
|
||||
|
||||
const saveResult = await saveSelectedGoalToServer(selectedGoalId);
|
||||
btnSetGoal.classList.remove('is-loading');
|
||||
btnSetGoal.removeAttribute('aria-disabled');
|
||||
|
||||
if (!saveResult.ok) {
|
||||
const msg = saveResult.message ? (' (' + saveResult.message + ')') : '';
|
||||
alert('목표 저장에 실패했습니다. 잠시 후 다시 시도해주세요.' + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
closeGoalLayer();
|
||||
applySelectedState(selectedGoalId);
|
||||
window.location.href = nextUrl;
|
||||
});
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// [6] 선택 후 상태 적용
|
||||
// ====================================================
|
||||
const selectedGoalSection = document.getElementById('selectedGoalSection');
|
||||
const selectedGoalTitle = document.getElementById('selectedGoalTitle');
|
||||
|
||||
function applySelectedState(goalId) {
|
||||
const goal = goals.find(function (g) { return g.id === goalId; });
|
||||
|
||||
document.querySelectorAll('.goal-item').forEach(function (item) {
|
||||
item.classList.remove('is-selected');
|
||||
const defaultArea = item.querySelector('.card-default-area');
|
||||
if (defaultArea) defaultArea.hidden = false;
|
||||
});
|
||||
|
||||
const selectedItem = document.querySelector('.goal-item[data-goal-id="' + goalId + '"]');
|
||||
if (selectedItem) {
|
||||
selectedItem.classList.add('is-selected');
|
||||
selectedItem.hidden = true;
|
||||
}
|
||||
|
||||
if (selectedGoalSection && selectedGoalTitle && goal) {
|
||||
selectedGoalTitle.textContent = goal.title;
|
||||
selectedGoalSection.classList.remove('hidden');
|
||||
selectedGoalSection.hidden = false;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.intro-state').forEach(function (el) {
|
||||
const isDone = el.classList.contains('intro-state--done');
|
||||
el.hidden = !isDone;
|
||||
el.classList.toggle('hidden', !isDone);
|
||||
});
|
||||
|
||||
if (btnSelectGoal) btnSelectGoal.textContent = '추가 목표 고르기';
|
||||
var bookshelf = document.getElementById('bookshelf');
|
||||
if (bookshelf) bookshelf.classList.add('has-selected');
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// [7] 카드 클릭 이벤트
|
||||
// ====================================================
|
||||
document.querySelectorAll('.goal-card').forEach(function (card) {
|
||||
card.addEventListener('click', function () {
|
||||
const item = card.closest('.goal-item');
|
||||
const goalId = parseInt(item.dataset.goalId, 10);
|
||||
openGoalLayer(goalId);
|
||||
});
|
||||
});
|
||||
|
||||
if (btnSelectGoal) {
|
||||
btnSelectGoal.addEventListener('click', function () {
|
||||
const firstAvailable = selectedGoalId
|
||||
? goals.find(function (g) { return g.id !== selectedGoalId; })
|
||||
: goals[0];
|
||||
if (firstAvailable) openGoalLayer(firstAvailable.id);
|
||||
});
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// [8] 팝업 닫기: 닫기 버튼, 배경 클릭, ESC 키
|
||||
// ====================================================
|
||||
if (btnCloseLayer) btnCloseLayer.addEventListener('click', closeGoalLayer);
|
||||
|
||||
goalLayer.addEventListener('click', function (e) {
|
||||
if (e.target === goalLayer) closeGoalLayer();
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && goalLayer.classList.contains('is-open')) {
|
||||
closeGoalLayer();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user