1185 lines
42 KiB
PHP
1185 lines
42 KiB
PHP
<?php
|
||
require_once __DIR__ . '/../bbs/auth.php';
|
||
edu_require_login();
|
||
?>
|
||
<!doctype html>
|
||
<html lang="ko">
|
||
<head>
|
||
<?php include(__DIR__ . "/_include/_head.php") ?>
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap" rel="stylesheet">
|
||
</head>
|
||
<?php
|
||
$SET_PREFIX = 'L'; //L=리더십(기본값), I=인사이트
|
||
$activeCate = isset($_GET['cate']) ? trim($_GET['cate']) : '';
|
||
require_once __DIR__ . '/../bbs/category_init_data.php';
|
||
?>
|
||
<body>
|
||
<div class="wrap leadership">
|
||
<?php include(__DIR__ . "/_include/_header.php") ?>
|
||
<!-- container -->
|
||
<div class="container">
|
||
<div class="container-inner">
|
||
<!-- editor's pick -->
|
||
<section class="leadership-hero">
|
||
<div class="leadership-inner hero-top hero-breadcrumb">
|
||
<ul class="breadcrumb" aria-label="breadcrumb">
|
||
<li><a href="./index.php">홈</a></li>
|
||
<li><a href="./leadership.php">리더십</a></li>
|
||
<li><span class="current"></span></li>
|
||
</ul>
|
||
</div>
|
||
<!-- editor's pick -->
|
||
|
||
<!-- 리더십 고정 배너 3종: PC 1442×460 / 모바일 360×234 -->
|
||
<div class="hero-banner">
|
||
<div class="swiper hero-swiper">
|
||
<div class="swiper-wrapper">
|
||
|
||
<?php foreach ($array_banner_img as $i => $bn): ?>
|
||
<div class="swiper-slide">
|
||
<div class="banner-img">
|
||
<picture>
|
||
<source media="(min-width: 769px)" srcset="<?= $bn['normal'] ?>">
|
||
<source media="(max-width: 768px)" srcset="<?= $bn['mobile'] ?>">
|
||
<img src="<?= $bn['normal'] ?>" alt="<?= $bn['title'] ?>">
|
||
</picture>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="swiper-pagination hero-pagination" aria-hidden="true"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Tabs -->
|
||
<div class="leadership-tabs" aria-label="카테고리">
|
||
<div class="leadership-inner">
|
||
<div class="leadership-tabs-list" role="tablist" aria-label="카테고리 탭">
|
||
|
||
<?php foreach ($array_tab_info as $i => $ti):
|
||
$isActive = ($activeCate !== '') ? ($ti['base_code'] === $activeCate) : ($i === 0);
|
||
?>
|
||
<button class="leadership-tab <?php if($isActive){?>is-active<?php }?>" type="button" role="tab" aria-selected="<?php if($isActive){?>true<?php }else{?>false<?php }?> " data-cate="<?= $ti['base_code'] ?>">
|
||
<span class="tab-icon"><img src="<?= $ti['src'] ?>" alt="" /></span>
|
||
<span class="tab-text"><?= $ti['code_name'] ?></span>
|
||
</button>
|
||
<?php endforeach; ?>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- video list -->
|
||
|
||
<section class="leadership-video-list">
|
||
<div class="leadership-inner">
|
||
<div class="list-head">
|
||
<span class="total">전체 <em></em></span>
|
||
<div class="list-options">
|
||
<div class="select-wrap">
|
||
<select class="select-sort" title="정렬">
|
||
<option value="view" selected>조회수</option>
|
||
<option value="latest" >업데이트</option>
|
||
<option value="seen">내가본컨텐츠</option>
|
||
<option value="unseen">안본컨텐츠</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 탭선택에 따른 동적 컨텐츠영역 -->
|
||
<ul class="video-grid" id="video-list"></ul>
|
||
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- // container -->
|
||
</div>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
// Hero Swiper
|
||
new Swiper('.hero-swiper', {
|
||
loop: true,
|
||
autoplay: {
|
||
delay: 4000,
|
||
disableOnInteraction: false,
|
||
},
|
||
speed: 600,
|
||
pagination: {
|
||
el: '.hero-pagination',
|
||
clickable: true,
|
||
},
|
||
});
|
||
|
||
// Tabs
|
||
const tabs = Array.from(document.querySelectorAll('.leadership-tab'));
|
||
if (!tabs.length) return;
|
||
|
||
tabs.forEach(function (tab) {
|
||
tab.addEventListener('click', function () {
|
||
tabs.forEach(function (t) {
|
||
t.classList.remove('is-active');
|
||
t.setAttribute('aria-selected', 'false');
|
||
});
|
||
|
||
let currentText = $(this).find('.tab-text').text();
|
||
console.log('tabs');
|
||
console.log(currentText);
|
||
$('.current').text(currentText);
|
||
|
||
tab.classList.add('is-active');
|
||
tab.setAttribute('aria-selected', 'true');
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
<script>
|
||
$( document ).ready(function() {
|
||
/*
|
||
let currentText = $('.current').find('.tab-text').text();
|
||
if(currentText==""){$('.current').text("리더십 입문");}
|
||
*/
|
||
let firstTabText = $('.leadership-tab.is-active').find('.tab-text').text();
|
||
if($('.current').text() == "" && firstTabText != ""){
|
||
$('.current').text(firstTabText);
|
||
}
|
||
});
|
||
|
||
$(function () {
|
||
|
||
let page = 1;
|
||
let loading = false;
|
||
let lastPage = false;
|
||
let requestSeq = 0;
|
||
|
||
//let category = $('.leadership-tab.is-active').data('cate') || 'CA200L01';
|
||
var urlParams = new URLSearchParams(window.location.search);
|
||
var urlCate = urlParams.get('cate') || '';
|
||
if (urlCate) {
|
||
$('.leadership-tab').removeClass('is-active').attr('aria-selected', 'false');
|
||
var $matchTab = $('.leadership-tab[data-cate="' + urlCate + '"]');
|
||
if ($matchTab.length) {
|
||
$matchTab.addClass('is-active').attr('aria-selected', 'true');
|
||
}
|
||
}
|
||
let category = urlCate || $('.leadership-tab.is-active').data('cate') || 'CA200<?= $SET_PREFIX ?>01';
|
||
let sort = $('.select-sort').val() || 'latest';
|
||
|
||
loadVideos();
|
||
|
||
$('.leadership-tab').on('click', function () {
|
||
if (loading) return;
|
||
|
||
$('.leadership-tab').removeClass('is-active').attr('aria-selected', 'false');
|
||
$(this).addClass('is-active').attr('aria-selected', 'true');
|
||
|
||
category = $(this).data('cate');
|
||
resetList(true);
|
||
loadVideos();
|
||
});
|
||
|
||
$('.select-sort').on('change', function () {
|
||
if (loading) return;
|
||
|
||
sort = $(this).val();
|
||
resetList(true);
|
||
loadVideos();
|
||
});
|
||
|
||
//$('.container').on('scroll', function () {
|
||
$('.container-inner').on('scroll', function () {
|
||
console.log(".container scroll");
|
||
if (loading || lastPage) return;
|
||
|
||
const scrollTop = this.scrollTop;
|
||
const windowHeight = this.clientHeight;
|
||
const docHeight = this.scrollHeight;
|
||
|
||
console.log("scrollTop="+scrollTop);
|
||
console.log("windowHeight="+windowHeight);
|
||
console.log("docHeight="+docHeight);
|
||
|
||
console.log("scrollTop + windowHeight=");
|
||
console.log((scrollTop + windowHeight));
|
||
|
||
console.log("docHeight - 100=");
|
||
console.log((docHeight - 100));
|
||
|
||
if (scrollTop + windowHeight >= docHeight - 100) {
|
||
page++;
|
||
loadVideos();
|
||
}
|
||
});
|
||
|
||
function resetList(moveTop) {
|
||
page = 1;
|
||
lastPage = false;
|
||
$('#video-list').empty();
|
||
|
||
if (moveTop) {
|
||
$('.container').scrollTop(0);
|
||
}
|
||
}
|
||
|
||
function setLoading(isLoading) {
|
||
loading = isLoading;
|
||
}
|
||
|
||
function normalizeBookmarkMarkup() {
|
||
// 서버 렌더 템플릿의 인라인 onclick(event.stopPropagation()) 때문에
|
||
// 위임 이벤트가 막히는 경우가 있어 제거한다.
|
||
$('#video-list .bookmark').removeAttr('onclick');
|
||
}
|
||
|
||
function applyKeywordDesc() {
|
||
$('#video-list .video-item').each(function () {
|
||
var $item = $(this);
|
||
var rawKeywords = String(
|
||
$item.attr('data-keywords')
|
||
|| $item.data('keywords')
|
||
|| $item.attr('data-keyword')
|
||
|| $item.data('keyword')
|
||
|| ''
|
||
).trim();
|
||
|
||
if (!rawKeywords) return;
|
||
|
||
var keywordText = rawKeywords
|
||
.split(/[\,\|]/)
|
||
.map(function (kw) { return String(kw || '').trim(); })
|
||
.filter(Boolean)
|
||
.map(function (kw) { return kw.indexOf('#') === 0 ? kw : ('#' + kw); })
|
||
.join(' ');
|
||
|
||
if (!keywordText) return;
|
||
|
||
var $desc = $item.find('.item-desc').first();
|
||
if ($desc.length) {
|
||
$desc.text(keywordText);
|
||
}
|
||
});
|
||
}
|
||
|
||
function loadVideos() {
|
||
requestSeq++;
|
||
const currentRequestSeq = requestSeq;
|
||
|
||
setLoading(true);
|
||
|
||
$.ajax({
|
||
url: '/ajax/get_video_list.php?SET_PREFIX=<?= $SET_PREFIX ?>',
|
||
type: 'GET',
|
||
dataType: 'json',
|
||
cache: false,
|
||
data: {
|
||
category: category,
|
||
sort: sort,
|
||
page: page
|
||
},
|
||
success: function (res) {
|
||
if (currentRequestSeq !== requestSeq) return;
|
||
|
||
if (!res || res.success !== true) {
|
||
if (page > 1) page--;
|
||
return;
|
||
}
|
||
|
||
const html = $.trim(res.html || '');
|
||
const totalCount = parseInt(res.total_count, 10) || 0;
|
||
|
||
$('.total em').text(totalCount);
|
||
|
||
if (page === 1) {
|
||
$('#video-list').html(html);
|
||
normalizeBookmarkMarkup();
|
||
applyKeywordDesc();
|
||
|
||
if (html === '') {
|
||
lastPage = true;
|
||
$('#video-list').html(
|
||
'<li class="video-item video-empty">' +
|
||
'<div class="item-info">' +
|
||
'<strong class="item-title">등록된 콘텐츠가 없습니다.</strong>' +
|
||
'</div>' +
|
||
'</li>'
|
||
);
|
||
}
|
||
} else {
|
||
if (html === '') {
|
||
lastPage = true;
|
||
page--;
|
||
} else {
|
||
$('#video-list').append(html);
|
||
normalizeBookmarkMarkup();
|
||
applyKeywordDesc();
|
||
}
|
||
}
|
||
},
|
||
error: function () {
|
||
if (page > 1) page--;
|
||
},
|
||
complete: function () {
|
||
if (currentRequestSeq === requestSeq) {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
});
|
||
</script>
|
||
|
||
<!-- ============================================ -->
|
||
<!-- 영상 모달 댓글 스타일 (온보딩 동일) -->
|
||
<!-- ============================================ -->
|
||
<style>
|
||
/* #leadershipVideoModal .comment-list { list-style: none; margin: 0; padding: 0; }
|
||
#leadershipVideoModal .comment-list li { padding: 0; border-bottom: none; }
|
||
#leadershipVideoModal .comment-list li.empty-comment { padding: 20px; text-align: center; color: rgba(255,255,255,0.4); font-size: 13px; }
|
||
#leadershipVideoModal .comment-list .comment-info { display: flex; align-items: flex-start; }
|
||
#leadershipVideoModal .comment-list .comment-info .photo { flex-shrink: 0; margin-right: 6px; display: flex; align-items: center; }
|
||
#leadershipVideoModal .comment-list .comment-info .photo img { width: 20px; height: 20px; border-radius: 50%; }
|
||
#leadershipVideoModal .comment-list .comment-info .user-comment { flex: 1; min-width: 0; display: flex; align-items: center; }
|
||
#leadershipVideoModal .comment-list .comment-info .user-comment .user-name { font-size: 13px; color: #ccc; white-space: nowrap; flex-shrink: 0; margin-right: 8px; }
|
||
#leadershipVideoModal .comment-list .comment-info .user-comment .user-text { flex: 1; background: transparent; border: none; color: #fff; font-size: 13px; line-height: 1.4; resize: none; padding: 10px 0 0 0; word-break: break-word; font-family: inherit; }
|
||
#leadershipVideoModal .comment-list .comment-info .user-comment .user-text:disabled { opacity: 1; cursor: default; padding-top: 10px;}
|
||
#leadershipVideoModal .comment-list .comment-info .user-comment .user-text:not(:disabled) { border: 1px solid #555; border-radius: 4px; padding: 4px 8px; background: #2a2a2a; }
|
||
#leadershipVideoModal .comment-list .comment-info .actions { display: flex; gap: 4px; align-items: center; flex-shrink: 0; margin-left: 8px; align-self: center; }
|
||
#leadershipVideoModal .comment-list .comment-info .actions button { padding: 3px 8px; font-size: 12px; border: 1px solid #555; border-radius: 3px; background: #333; color: #ddd; cursor: pointer; white-space: nowrap; }
|
||
#leadershipVideoModal .comment-list .comment-info .actions button:hover { background: #555; color: #fff; }
|
||
#leadershipVideoModal .comment-list li.editing .user-text { border: 1px solid #00ffcc !important; } */
|
||
|
||
/* 댓글 영역 고정 레이아웃을 유지하기 위해 추천 목록 ul에만 스크롤 적용 */
|
||
#leadershipVideoModal .video-side .video-list {
|
||
overflow: hidden;
|
||
}
|
||
|
||
#leadershipVideoModal #recommendedList {
|
||
max-height: none;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
overscroll-behavior: contain;
|
||
padding-right: 4px;
|
||
}
|
||
|
||
#leadershipVideoModal #recommendedList::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
#leadershipVideoModal #recommendedList::-webkit-scrollbar-thumb {
|
||
background: rgba(255, 255, 255, 0.35);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
#leadershipVideoModal #recommendedList::-webkit-scrollbar-track {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
</style>
|
||
|
||
<!-- ============================================ -->
|
||
<!-- 영상 모달 (video.php 구조 참고) -->
|
||
<!-- ============================================ -->
|
||
<div class="modal video" id="leadershipVideoModal" style="display:none">
|
||
<div class="modal-content">
|
||
<div class="modal-body">
|
||
<div class="video-contents">
|
||
<div class="video-area">
|
||
<div class="video-box">
|
||
<div id="videoPlayer"></div>
|
||
</div>
|
||
</div>
|
||
<div class="video-info">
|
||
<div class="tit-box">
|
||
<div class="meta">
|
||
<span id="modalCategoryName"></span>
|
||
<em id="modalSubCategory"></em>
|
||
</div>
|
||
<h3 id="modalTitle"></h3>
|
||
<label class="bookmark" for="leadership-bookmark-chk">
|
||
<input id="leadership-bookmark-chk" type="checkbox" value="" />
|
||
<span>북마크</span>
|
||
</label>
|
||
</div>
|
||
<div class="desc" id="modalDesc"></div>
|
||
</div>
|
||
</div>
|
||
<div class="video-side">
|
||
<div class="video-header">
|
||
<h5 class="tit">관련영상</h5>
|
||
<span class="badge" id="modalBadge">리더십</span>
|
||
<span class="close">×</span>
|
||
</div>
|
||
<div class="video-list">
|
||
<ul id="recommendedList">
|
||
<!-- JS로 동적 렌더링 -->
|
||
</ul>
|
||
</div>
|
||
<div class="comment-wrap">
|
||
<!-- 댓글 목록 -->
|
||
<div class="comment-list-wrap">
|
||
<ul class="comment-list">
|
||
<li class="empty-comment" style="padding:20px; text-align:center; color:rgba(255,255,255,0.4); font-size:13px;">작성된 댓글이 없습니다.</li>
|
||
</ul>
|
||
</div>
|
||
<!-- 댓글 입력 -->
|
||
<div class="comment-box">
|
||
<textarea placeholder="댓글을 작성해주세요"></textarea>
|
||
<div class="btn-area">
|
||
<button class="btn-cancel" disabled>취소</button>
|
||
<button class="btn-save" disabled>등록</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============================================ -->
|
||
<!-- 영상 모달 JS (클릭 → 모달 열기 / 추천영상 / 댓글) -->
|
||
<!-- ============================================ -->
|
||
<script>
|
||
$(function () {
|
||
var API_BASE = '/bbs/api';
|
||
var $modal = $('#leadershipVideoModal');
|
||
var currentContentId = null;
|
||
var editingCommentId = null;
|
||
|
||
// ── YouTube IFrame API 시청 추적 변수 ──
|
||
var ytPlayer = null;
|
||
var trackingInterval = null;
|
||
var lastSaveTime = 0;
|
||
var lastCurrentTime = 0;
|
||
|
||
// YouTube IFrame API 스크립트 로드
|
||
if (!document.getElementById('youtube-iframe-api')) {
|
||
var ytScript = document.createElement('script');
|
||
ytScript.id = 'youtube-iframe-api';
|
||
ytScript.src = 'https://www.youtube.com/iframe_api';
|
||
ytScript.async = true;
|
||
document.head.appendChild(ytScript);
|
||
}
|
||
|
||
// ── YouTube 비디오 ID 추출 ──
|
||
function extractVideoId(url) {
|
||
if (!url) return '';
|
||
var videoId = url;
|
||
if (url.indexOf('youtube.com/watch') > -1) {
|
||
try { videoId = new URL(url).searchParams.get('v') || url; } catch (e) {}
|
||
} else if (url.indexOf('youtu.be/') > -1) {
|
||
videoId = url.split('youtu.be/')[1].split(/[?&#]/)[0];
|
||
} else if (url.indexOf('youtube.com/embed/') > -1) {
|
||
videoId = url.split('youtube.com/embed/')[1].split(/[?&#]/)[0];
|
||
}
|
||
if (videoId && videoId.indexOf('/') === -1 && videoId.indexOf('.') === -1) {
|
||
return videoId;
|
||
}
|
||
return '';
|
||
}
|
||
|
||
// ── YT.Player 생성 ──
|
||
function initYTPlayer(videoId, startSeconds) {
|
||
destroyYTPlayer();
|
||
startSeconds = Math.floor(startSeconds || 0);
|
||
|
||
var createPlayer = function () {
|
||
ytPlayer = new YT.Player('videoPlayer', {
|
||
height: '100%',
|
||
width: '100%',
|
||
videoId: videoId,
|
||
playerVars: {
|
||
autoplay: 1,
|
||
controls: 1,
|
||
rel: 0,
|
||
modestbranding: 1,
|
||
enablejsapi: 1,
|
||
start: startSeconds
|
||
},
|
||
events: {
|
||
'onReady': function (event) {
|
||
if (event.target && typeof event.target.playVideo === 'function') {
|
||
event.target.playVideo();
|
||
}
|
||
},
|
||
'onStateChange': function (event) {
|
||
handlePlayerStateChange(event);
|
||
},
|
||
'onError': function (event) {
|
||
console.error('[Leadership] Player Error:', event.data);
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
if (typeof YT !== 'undefined' && YT.Player && typeof YT.Player === 'function') {
|
||
createPlayer();
|
||
} else {
|
||
// YT API 아직 로드 안 됨 → 대기
|
||
var checkYt = setInterval(function () {
|
||
if (typeof YT !== 'undefined' && YT.Player && typeof YT.Player === 'function') {
|
||
clearInterval(checkYt);
|
||
createPlayer();
|
||
}
|
||
}, 500);
|
||
setTimeout(function () { clearInterval(checkYt); }, 10000);
|
||
}
|
||
}
|
||
|
||
// ── 플레이어 파괴 ──
|
||
function destroyYTPlayer() {
|
||
stopTracking();
|
||
if (ytPlayer && typeof ytPlayer.destroy === 'function') {
|
||
try { ytPlayer.destroy(); } catch (e) {}
|
||
}
|
||
ytPlayer = null;
|
||
// YT.Player가 div를 iframe으로 교체하므로 다시 div를 복원
|
||
var $box = $modal.find('.video-box');
|
||
if (!$box.find('#videoPlayer').length) {
|
||
$box.html('<div id="videoPlayer"></div>');
|
||
}
|
||
}
|
||
|
||
// ── 플레이어 상태 변경 핸들러 (VideoModalBase 패턴) ──
|
||
function handlePlayerStateChange(event) {
|
||
if (event.data === YT.PlayerState.PLAYING) {
|
||
startTracking();
|
||
} else {
|
||
stopTracking();
|
||
if (event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.ENDED) {
|
||
saveLearningProgress(Math.floor(lastSaveTime), 'N');
|
||
lastSaveTime = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ── 시청 추적 시작 (1초 주기) ──
|
||
function startTracking() {
|
||
if (trackingInterval) return;
|
||
lastSaveTime = 0;
|
||
|
||
trackingInterval = setInterval(function () {
|
||
if (!ytPlayer || typeof ytPlayer.getCurrentTime !== 'function') return;
|
||
|
||
var playerState = (typeof ytPlayer.getPlayerState === 'function')
|
||
? ytPlayer.getPlayerState() : null;
|
||
if (playerState !== YT.PlayerState.PLAYING) return;
|
||
|
||
var currentTime = ytPlayer.getCurrentTime();
|
||
var diff = currentTime - lastCurrentTime;
|
||
if (Math.abs(diff) <= 5) {
|
||
lastSaveTime += 1;
|
||
}
|
||
lastCurrentTime = currentTime;
|
||
|
||
// 30초마다 서버에 heartbeat 전송
|
||
if (lastSaveTime >= 30) {
|
||
saveLearningProgress(lastSaveTime);
|
||
lastSaveTime = 0;
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
// ── 시청 추적 중지 ──
|
||
function stopTracking() {
|
||
if (trackingInterval) {
|
||
clearInterval(trackingInterval);
|
||
trackingInterval = null;
|
||
}
|
||
}
|
||
|
||
// ── 서버에 학습 진행상황 저장 (save_learning.php) ──
|
||
function saveLearningProgress(heartbeatSeconds, isWatching) {
|
||
if (!ytPlayer || !currentContentId) return;
|
||
if (typeof ytPlayer.getCurrentTime !== 'function') return;
|
||
|
||
var currentTime = Math.floor(ytPlayer.getCurrentTime());
|
||
var duration = Math.floor(ytPlayer.getDuration());
|
||
var incrementalWatch = Math.max(0, Math.floor(heartbeatSeconds || 0));
|
||
|
||
var params = new URLSearchParams({
|
||
content_id: String(currentContentId),
|
||
watch_tm: String(Math.max(0, currentTime)),
|
||
content_tm: String(Math.max(0, duration)),
|
||
all_tm_increment: String(incrementalWatch),
|
||
is_watching: isWatching === 'N' ? 'N' : 'Y'
|
||
});
|
||
|
||
fetch(API_BASE + '/save_learning.php', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||
body: params.toString(),
|
||
keepalive: true
|
||
}).then(function (r) { return r.json(); }).then(function (result) {
|
||
if (!result.success) {
|
||
console.error('[Leadership] Save Learning Failed:', result.message);
|
||
}
|
||
}).catch(function (e) {
|
||
console.error('[Leadership] Save Learning Error:', e);
|
||
});
|
||
}
|
||
|
||
// ── 영상 카드 클릭 → 모달 열기 ──
|
||
$(document).on('click', '#video-list .video-item .card-link', function (e) {
|
||
if ($(e.target).closest('.bookmark').length) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
return;
|
||
}
|
||
e.preventDefault();
|
||
var $item = $(this).closest('.video-item');
|
||
|
||
var contentId = $item.data('content-id') || $item.attr('data-content-id') || '';
|
||
var videoUrl = $item.data('content-url') || $item.attr('data-content-url') || '';
|
||
var title = $item.data('title') || $item.find('.item-title').text().trim() || '';
|
||
var desc = $item.data('description') || '';
|
||
var catName = $item.data('category-name') || $item.find('.item-category').text().trim() || '리더십';
|
||
var subCat = $item.data('sub-category') || '';
|
||
var watchTm = parseInt($item.data('watch-tm') || $item.attr('data-watch-tm') || '0', 10);
|
||
var contentTm = parseInt($item.data('content-tm') || $item.attr('data-content-tm') || '0', 10);
|
||
var isBookmarked = $item.find('.bookmark input[type="checkbox"]').is(':checked');
|
||
|
||
if (!contentId) {
|
||
console.warn('[VideoModal] content-id가 없습니다.');
|
||
return;
|
||
}
|
||
|
||
openModal({
|
||
contentId: contentId,
|
||
videoUrl: videoUrl,
|
||
title: title,
|
||
description: desc,
|
||
categoryName: catName,
|
||
subCategory: subCat,
|
||
watchTm: watchTm,
|
||
contentTm: contentTm,
|
||
bookmark: isBookmarked
|
||
});
|
||
});
|
||
|
||
// ── 리스트 카드 북마크 토글/저장 ──
|
||
// input 클릭은 브라우저 기본 토글을 사용하고, label 영역 클릭만 수동 토글한다.
|
||
function saveListBookmark($chk, contentId, isActive) {
|
||
$chk.prop('disabled', true);
|
||
|
||
$.ajax({
|
||
url: '/bbs/api/save_wishlist.php',
|
||
type: 'POST',
|
||
data: { content_id: contentId, is_active: isActive },
|
||
dataType: 'json',
|
||
success: function (res) {
|
||
if (!res || res.success !== true) {
|
||
$chk.prop('checked', isActive !== '1');
|
||
return;
|
||
}
|
||
|
||
// 같은 영상을 모달에서 보고 있으면 모달 북마크도 동기화
|
||
if (currentContentId && String(currentContentId) === String(contentId)) {
|
||
$modal.find('.bookmark input[type="checkbox"]').prop('checked', isActive === '1');
|
||
}
|
||
},
|
||
error: function () {
|
||
$chk.prop('checked', isActive !== '1');
|
||
},
|
||
complete: function () {
|
||
$chk.prop('disabled', false);
|
||
}
|
||
});
|
||
}
|
||
|
||
$(document).on('click', '#video-list .bookmark', function (e) {
|
||
if ($(e.target).is('input[type="checkbox"]')) {
|
||
// input은 기본 토글을 허용하고 change에서 저장
|
||
e.stopPropagation();
|
||
return;
|
||
}
|
||
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
|
||
var $item = $(this).closest('.video-item');
|
||
var contentId = String($item.data('content-id') || $item.attr('data-content-id') || '');
|
||
if (!contentId) return;
|
||
|
||
var $chk = $(this).find('input[type="checkbox"]');
|
||
if (!$chk.length || $chk.prop('disabled')) return;
|
||
|
||
$chk.prop('checked', !$chk.prop('checked')).trigger('change');
|
||
});
|
||
|
||
$(document).on('change', '#video-list .bookmark input[type="checkbox"]', function (e) {
|
||
e.stopPropagation();
|
||
|
||
var $chk = $(this);
|
||
var $item = $chk.closest('.video-item');
|
||
var contentId = String($item.data('content-id') || $item.attr('data-content-id') || '');
|
||
if (!contentId) return;
|
||
|
||
var isActive = $chk.is(':checked') ? '1' : '0';
|
||
saveListBookmark($chk, contentId, isActive);
|
||
});
|
||
|
||
// ── 모달 열기 ──
|
||
function adjustRecommendedListHeight() {
|
||
if (!$modal.is(':visible')) return;
|
||
|
||
var $videoListWrap = $modal.find('.video-list');
|
||
var $list = $modal.find('#recommendedList');
|
||
var $commentWrap = $modal.find('.comment-wrap');
|
||
if (!$videoListWrap.length || !$list.length || !$commentWrap.length) return;
|
||
|
||
var listTop = $videoListWrap.offset().top;
|
||
var commentTop = $commentWrap.offset().top;
|
||
if (!Number.isFinite(listTop) || !Number.isFinite(commentTop)) return;
|
||
|
||
var availableHeight = Math.floor(commentTop - listTop - 8);
|
||
if (availableHeight < 120) availableHeight = 120;
|
||
|
||
$list.css('max-height', availableHeight + 'px');
|
||
}
|
||
|
||
function openModal(info) {
|
||
currentContentId = info.contentId;
|
||
editingCommentId = null;
|
||
lastSaveTime = 0;
|
||
lastCurrentTime = Math.floor(info.watchTm || 0);
|
||
|
||
// YouTube IFrame API 플레이어 세팅
|
||
var videoId = extractVideoId(info.videoUrl);
|
||
if (videoId) {
|
||
initYTPlayer(videoId, info.watchTm || 0);
|
||
}
|
||
|
||
// 서버에서 최신 watch_tm 조회 후 재생 위치 보정
|
||
$.ajax({
|
||
url: '/bbs/myclass/api/get_video_time.php',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({ content_id: info.contentId }),
|
||
dataType: 'json',
|
||
success: function(res) {
|
||
if (res.success && res.watch_tm > 0) {
|
||
var serverWatchTm = parseInt(res.watch_tm, 10);
|
||
if (ytPlayer && typeof ytPlayer.seekTo === 'function' && serverWatchTm > (info.watchTm || 0)) {
|
||
ytPlayer.seekTo(serverWatchTm, true);
|
||
lastCurrentTime = serverWatchTm;
|
||
}
|
||
// 카드 data-watch-tm 동기화
|
||
$('#video-list .video-item[data-content-id="' + info.contentId + '"]').attr('data-watch-tm', serverWatchTm);
|
||
}
|
||
}
|
||
});
|
||
|
||
// 영상 정보
|
||
$modal.find('#modalTitle').text(info.title);
|
||
// 설명: 줄바꿈을 <br>로 변환하여 표시
|
||
var descHtml = $('<div>').text(info.description || '').html().replace(/\n/g, '<br>');
|
||
$modal.find('#modalDesc').html(descHtml);
|
||
$modal.find('#modalCategoryName').text(info.categoryName || '리더십');
|
||
$modal.find('#modalSubCategory').text(info.subCategory || '');
|
||
$modal.find('#modalBadge').text(info.categoryName || '리더십');
|
||
|
||
// 추천영상 리스트
|
||
buildRecommendedList(info.contentId);
|
||
|
||
// 댓글 로드
|
||
loadComments(info.contentId);
|
||
resetCommentForm();
|
||
|
||
// 북마크 상태 동기화
|
||
syncBookmark(info.contentId, info.bookmark);
|
||
|
||
// 모달 표시
|
||
$modal.show();
|
||
$('body').css('overflow', 'hidden');
|
||
|
||
// 추천영역을 댓글 시작점까지 확장
|
||
setTimeout(adjustRecommendedListHeight, 0);
|
||
}
|
||
|
||
// ── 모달 닫기 (진행상황 저장 후 닫기) ──
|
||
function closeModal() {
|
||
// 마지막 시청 진행상황 저장
|
||
stopTracking();
|
||
if (ytPlayer && currentContentId && typeof ytPlayer.getCurrentTime === 'function') {
|
||
var currentTime = Math.floor(ytPlayer.getCurrentTime());
|
||
// 카드의 data-watch-tm 업데이트 (재오픈 시 적용)
|
||
$('#video-list .video-item[data-content-id="' + currentContentId + '"]').attr('data-watch-tm', currentTime);
|
||
saveLearningProgress(Math.floor(lastSaveTime), 'N');
|
||
}
|
||
lastSaveTime = 0;
|
||
|
||
destroyYTPlayer();
|
||
$modal.hide();
|
||
$('body').css('overflow', '');
|
||
currentContentId = null;
|
||
editingCommentId = null;
|
||
}
|
||
|
||
$modal.on('click', '.close', closeModal);
|
||
$modal.on('click', function (e) {
|
||
if ($(e.target).hasClass('modal')) closeModal();
|
||
});
|
||
$(document).on('keydown', function (e) {
|
||
if (e.key === 'Escape' && $modal.is(':visible')) closeModal();
|
||
});
|
||
|
||
// ── 북마크 동기화 ──
|
||
function syncBookmark(contentId, isBookmarked) {
|
||
var $chk = $modal.find('.bookmark input[type="checkbox"]');
|
||
if (!$chk.length) return;
|
||
if (isBookmarked !== undefined) {
|
||
$chk.prop('checked', !!isBookmarked);
|
||
} else {
|
||
// 서버에서 북마크 상태 조회
|
||
$.ajax({
|
||
url: '/bbs/myclass/api/get_video_time.php',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({ content_id: contentId }),
|
||
dataType: 'json',
|
||
success: function(res) {
|
||
if (res.success) {
|
||
$chk.prop('checked', !!res.is_bookmarked);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// ── 북마크 토글 이벤트 ──
|
||
$modal.on('change', '.bookmark input[type="checkbox"]', function () {
|
||
var $chk = $(this);
|
||
var isActive = $chk.is(':checked') ? '1' : '0';
|
||
if (!currentContentId) return;
|
||
$chk.prop('disabled', true);
|
||
$.ajax({
|
||
url: '/bbs/api/save_wishlist.php',
|
||
type: 'POST',
|
||
data: { content_id: String(currentContentId), is_active: isActive },
|
||
dataType: 'json',
|
||
success: function (res) {
|
||
if (!res || res.success !== true) {
|
||
$chk.prop('checked', !$chk.is(':checked'));
|
||
// alert(res?.message || '북마크 저장에 실패했습니다.');
|
||
} else {
|
||
// 목록 카드의 북마크 상태도 동기화
|
||
var $card = $('#video-list .video-item[data-content-id="' + currentContentId + '"] .bookmark input');
|
||
$card.prop('checked', isActive === '1');
|
||
}
|
||
},
|
||
error: function () {
|
||
$chk.prop('checked', !$chk.is(':checked'));
|
||
alert('북마크 저장 중 오류가 발생했습니다.');
|
||
},
|
||
complete: function () {
|
||
$chk.prop('disabled', false);
|
||
}
|
||
});
|
||
});
|
||
|
||
// ── 추천영상 리스트 구성 (키워드 기반 API) ──
|
||
function buildRecommendedList(contentId) {
|
||
var $list = $modal.find('#recommendedList');
|
||
$list.html('<li style="padding:20px; text-align:center; color:rgba(255,255,255,0.4); font-size:13px;">추천 영상 로딩 중...</li>');
|
||
|
||
if (!contentId) {
|
||
$list.html('<li style="padding:20px; text-align:center; color:rgba(255,255,255,0.4); font-size:13px;">관련 추천 영상이 없습니다.</li>');
|
||
return;
|
||
}
|
||
|
||
$.getJSON(API_BASE + '/get_recommend_videos.php', { content_id: contentId })
|
||
.done(function (data) {
|
||
if (!data.success || !data.videos || data.videos.length === 0) {
|
||
$list.html('<li style="padding:20px; text-align:center; color:rgba(255,255,255,0.4); font-size:13px;">관련 추천 영상이 없습니다.</li>');
|
||
// 키워드 배지 숨기기
|
||
$modal.find('#modalBadge').hide();
|
||
return;
|
||
}
|
||
|
||
// 키워드 배지 업데이트
|
||
if (data.keywords && data.keywords.length > 0) {
|
||
$modal.find('#modalBadge').text(data.keywords.join(', ')).show();
|
||
} else {
|
||
$modal.find('#modalBadge').hide();
|
||
}
|
||
|
||
$list.empty();
|
||
var catClassMap = {
|
||
'CA10001': 'myclass', 'CA10002': 'onboarding', 'CA10003': 'legal',
|
||
'CA10004': 'leader', 'CA10005': 'insight', 'CA10006': 'biztrend'
|
||
};
|
||
|
||
data.videos.forEach(function (v) {
|
||
var safeTitle = $('<div>').text(v.title || '').html();
|
||
var safeCat = $('<div>').text(v.category_name || '').html();
|
||
var thumb = v.thumbnail || '/img/video/img_thumb_01.png';
|
||
var catClass = catClassMap[v.category_code] || '';
|
||
|
||
var li =
|
||
'<li>' +
|
||
'<a href="#" class="list" ' +
|
||
'data-content-id="' + (v.content_id || '') + '" ' +
|
||
'data-content-url="' + (v.content_url || '').replace(/"/g, '"') + '" ' +
|
||
'data-title="' + (v.title || '').replace(/"/g, '"') + '" ' +
|
||
'data-description="' + (v.description || '').replace(/"/g, '"') + '" ' +
|
||
'data-category-name="' + (v.category_name || '').replace(/"/g, '"') + '" ' +
|
||
'data-sub-category="' + (v.subcate || '').replace(/"/g, '"') + '">' +
|
||
'<div class="thumb"><img src="' + thumb + '" alt="" /></div>' +
|
||
'<div class="txt-box">' +
|
||
'<div class="category ' + catClass + '">' + safeCat + '</div>' +
|
||
'<div class="title">' + safeTitle + '</div>' +
|
||
'</div>' +
|
||
'</a>' +
|
||
'</li>';
|
||
$list.append(li);
|
||
});
|
||
|
||
setTimeout(adjustRecommendedListHeight, 0);
|
||
})
|
||
.fail(function () {
|
||
$list.html('<li style="padding:20px; text-align:center; color:rgba(255,255,255,0.4); font-size:13px;">관련 추천 영상이 없습니다.</li>');
|
||
setTimeout(adjustRecommendedListHeight, 0);
|
||
});
|
||
}
|
||
|
||
$(window).on('resize', function () {
|
||
if ($modal.is(':visible')) {
|
||
adjustRecommendedListHeight();
|
||
}
|
||
});
|
||
|
||
// ── 추천영상 클릭 → 영상 전환 ──
|
||
$modal.on('click', '#recommendedList .list', function (e) {
|
||
e.preventDefault();
|
||
var $a = $(this);
|
||
// 현재 영상 진행상황 저장 후 전환
|
||
stopTracking();
|
||
if (ytPlayer && currentContentId && typeof ytPlayer.getCurrentTime === 'function') {
|
||
saveLearningProgress(Math.floor(lastSaveTime), 'N');
|
||
}
|
||
lastSaveTime = 0;
|
||
var recCid = $a.attr('data-content-id') || $a.data('content-id') || '';
|
||
var recSubCat = $a.attr('data-sub-category') || '';
|
||
// DOM fallback: 같은 content_id가 #video-list에 있으면 거기서 sub-category 보완
|
||
if (!recSubCat && recCid) {
|
||
var $card = $('#video-list .video-item[data-content-id="' + recCid + '"]');
|
||
if ($card.length) {
|
||
recSubCat = $card.attr('data-sub-category') || '';
|
||
}
|
||
}
|
||
openModal({
|
||
contentId: recCid,
|
||
videoUrl: $a.attr('data-content-url') || $a.data('content-url') || '',
|
||
title: $a.data('title') || $a.find('.title').text().trim(),
|
||
description: $a.data('description') || '',
|
||
categoryName: $a.data('category-name') || '리더십',
|
||
subCategory: recSubCat
|
||
});
|
||
});
|
||
|
||
// ══════════════════════════════════════════════
|
||
// 댓글 CRUD
|
||
// ══════════════════════════════════════════════
|
||
|
||
// ── 댓글 목록 로드 ──
|
||
function loadComments(contentId) {
|
||
var $commentList = $modal.find('.comment-list');
|
||
if (!contentId) return;
|
||
|
||
$.getJSON(API_BASE + '/get_comments.php', { content_id: contentId })
|
||
.done(function (data) {
|
||
if (data.success && Array.isArray(data.data)) {
|
||
renderComments(data.data);
|
||
} else {
|
||
$commentList.html('<li class="empty">등록된 댓글이 없습니다.</li>');
|
||
}
|
||
})
|
||
.fail(function () {
|
||
$commentList.html('<li class="empty">댓글을 불러올 수 없습니다.</li>');
|
||
});
|
||
}
|
||
|
||
// ── 댓글 렌더링 (온보딩 VideoModalBase 동일 구조) ──
|
||
function renderComments(comments) {
|
||
var $commentList = $modal.find('.comment-list');
|
||
if (!comments.length) {
|
||
$commentList.html('<li class="empty-comment" style="padding:20px; text-align:center; color:rgba(255,255,255,0.4); font-size:13px;">작성된 댓글이 없습니다.</li>');
|
||
return;
|
||
}
|
||
|
||
var html = comments.map(function (c) {
|
||
var safeComment = (c.comment || '')
|
||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||
var safeName = (c.member_name || '익명')
|
||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||
var actions = c.is_author
|
||
? '<div class="actions">' +
|
||
'<button type="button" class="btn-edit-comment" data-id="' + c.id + '">수정</button>' +
|
||
'<button type="button" class="btn-del-comment" data-id="' + c.id + '">삭제</button>' +
|
||
'</div>'
|
||
: '';
|
||
|
||
return '<li data-id="' + c.id + '">' +
|
||
'<div class="comment-info">' +
|
||
'<div class="photo"><img src="' + (c.profile_image || '/img/ico/ico_user.svg') + '" onerror="this.src=\'/img/ico/ico_user.svg\'" /></div>' +
|
||
'<div class="user-comment">' +
|
||
'<span class="user-name">' + safeName + '</span>' +
|
||
'<textarea class="user-text" disabled>' + safeComment + '</textarea>' +
|
||
'</div>' +
|
||
actions +
|
||
'</div>' +
|
||
'</li>';
|
||
}).join('');
|
||
|
||
$commentList.html(html);
|
||
adjustUserTextHeights();
|
||
}
|
||
|
||
// ── 댓글 textarea 높이 자동 조정 ──
|
||
function adjustUserTextHeights() {
|
||
$modal.find('.user-text').each(function () {
|
||
this.style.setProperty('overflow-y', 'hidden', 'important');
|
||
this.style.setProperty('overflow-x', 'hidden', 'important');
|
||
this.style.setProperty('max-height', 'none', 'important');
|
||
this.style.setProperty('height', '0px', 'important');
|
||
var h = this.scrollHeight;
|
||
this.style.setProperty('height', (h > 0 ? h : 40) + 'px', 'important');
|
||
});
|
||
}
|
||
|
||
// ── 댓글 인라인 수정 (온보딩 동일) ──
|
||
$modal.on('click', '.btn-edit-comment', function (e) {
|
||
e.preventDefault();
|
||
var $li = $(this).closest('li');
|
||
var $textarea = $li.find('.user-text');
|
||
var $btn = $(this);
|
||
|
||
if ($btn.text() === '수정') {
|
||
$textarea.prop('disabled', false).focus();
|
||
$btn.text('저장').css('color', '#00ffcc');
|
||
$li.addClass('editing');
|
||
} else {
|
||
var newComment = $textarea.val().trim();
|
||
if (!newComment) return;
|
||
if (newComment.length > COMMENT_MAX_LENGTH) {
|
||
alert('댓글은 200자까지 입력할 수 있습니다.');
|
||
$textarea.val($textarea.val().slice(0, COMMENT_MAX_LENGTH));
|
||
return;
|
||
}
|
||
var commentId = $btn.data('id');
|
||
|
||
$.ajax({
|
||
url: API_BASE + '/save_comment.php',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({ content_id: currentContentId, comment: newComment, id: commentId }),
|
||
success: function (data) {
|
||
if (data.success) {
|
||
$btn.text('수정').css('color', '');
|
||
$textarea.prop('disabled', true);
|
||
$li.removeClass('editing');
|
||
loadComments(currentContentId);
|
||
} else {
|
||
alert(data.message || '저장에 실패했습니다.');
|
||
}
|
||
},
|
||
error: function () { alert('저장 중 오류가 발생했습니다.'); }
|
||
});
|
||
}
|
||
});
|
||
|
||
// ── 댓글 삭제 (온보딩 동일) ──
|
||
$modal.on('click', '.btn-del-comment', function (e) {
|
||
e.preventDefault();
|
||
if (!confirm('정말 삭제하시겠습니까?')) return;
|
||
var commentId = $(this).data('id');
|
||
|
||
$.ajax({
|
||
url: API_BASE + '/delete_comment.php',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify({ id: commentId }),
|
||
success: function (data) {
|
||
if (data.success) {
|
||
loadComments(currentContentId);
|
||
} else {
|
||
alert(data.message || '삭제에 실패했습니다.');
|
||
}
|
||
},
|
||
error: function () { alert('삭제 중 오류가 발생했습니다.'); }
|
||
});
|
||
});
|
||
|
||
// ── 새 댓글 작성 ──
|
||
$modal.on('click', '.comment-box .btn-save', function () {
|
||
var $textarea = $modal.find('.comment-box textarea');
|
||
var comment = $textarea.val().trim();
|
||
if (!comment || !currentContentId) return;
|
||
|
||
if (comment.length > COMMENT_MAX_LENGTH) {
|
||
$textarea.val($textarea.val().slice(0, COMMENT_MAX_LENGTH));
|
||
alert('댓글은 200자까지 입력할 수 있습니다.');
|
||
return;
|
||
}
|
||
|
||
var payload = { content_id: currentContentId, comment: comment };
|
||
|
||
$.ajax({
|
||
url: API_BASE + '/save_comment.php',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(payload),
|
||
success: function (data) {
|
||
if (data.success) {
|
||
resetCommentForm();
|
||
loadComments(currentContentId);
|
||
} else {
|
||
alert(data.message || '저장에 실패했습니다.');
|
||
}
|
||
},
|
||
error: function () { alert('저장 중 오류가 발생했습니다.'); }
|
||
});
|
||
});
|
||
|
||
// ── 댓글 취소 ──
|
||
$modal.on('click', '.comment-box .btn-cancel', function () {
|
||
resetCommentForm();
|
||
});
|
||
|
||
var COMMENT_MAX_LENGTH = 200;
|
||
var _lastLengthAlertAt = 0;
|
||
|
||
// ── textarea 입력 → 버튼 활성화 + 200자 제한 ──
|
||
$modal.on('input', '.comment-box textarea', function () {
|
||
var $ta = $(this);
|
||
if ($ta.val().length > COMMENT_MAX_LENGTH) {
|
||
$ta.val($ta.val().slice(0, COMMENT_MAX_LENGTH));
|
||
var now = Date.now();
|
||
if (now - _lastLengthAlertAt > 800) {
|
||
_lastLengthAlertAt = now;
|
||
alert('댓글은 200자까지 입력할 수 있습니다.');
|
||
}
|
||
}
|
||
var hasText = $ta.val().trim().length > 0;
|
||
$modal.find('.btn-cancel').prop('disabled', !hasText);
|
||
$modal.find('.btn-save').prop('disabled', !hasText);
|
||
});
|
||
|
||
function resetCommentForm() {
|
||
var $ta = $modal.find('.comment-box textarea');
|
||
$ta.val('');
|
||
$ta.attr('maxlength', COMMENT_MAX_LENGTH);
|
||
$modal.find('.btn-cancel').prop('disabled', true);
|
||
$modal.find('.btn-save').prop('disabled', true).text('등록');
|
||
editingCommentId = null;
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|