window.loadingReplies = window.loadingReplies || {};
window.latestNewComment = null;
window.toggleReplies = function(cid) {
var container = $("#replies_" + cid);
if (!container.length) {
container = $("#reply_list_" + cid);
}
if (!container.length) return;
if (container.data("animating")) return;
if (container.is(":animated")) return;
if (!container.is(":visible")) {
container.data("animating", true);
container.removeClass("d-none").slideDown(function() {
container.data("animating", false);
});
if (container.children().length === 0) {
if (!window.loadingReplies[cid]) {
window.loadingReplies[cid] = true;
window.loadRepliesAndOpen(cid, 1, function(){
window.loadingReplies[cid] = false;
});
}
}
} else {
container.data("animating", true);
container.slideUp(function(){
container.addClass("d-none");
container.data("animating", false);
});
}
};
(function($){
$(document).ready(function(){
$(".reply-count-link").removeAttr("onclick");
var currentEditId = null;
var originalOuterHTML = "";
window.cancelParentEdit = function(){
if (!currentEditId) return;
var c = $("#comment_" + currentEditId);
c.replaceWith(originalOuterHTML);
currentEditId = null;
};
window.resetParentCommentForm = function($form){
if (!$form.length) return;
$form[0].reset();
};
$(document).off("click", ".comment-edit-btn").on("click", ".comment-edit-btn", function(e){
e.preventDefault();
var c = $(this).closest(".comment-item");
if(c.hasClass("child-comment")) return;
var cid = c.data("comment-id");
if(currentEditId && currentEditId !== cid){
$("#comment_" + currentEditId).replaceWith(originalOuterHTML);
currentEditId = null;
}
c.removeClass("py-2").addClass("p-2");
originalOuterHTML = $("#comment_" + cid).prop("outerHTML");
currentEditId = cid;
var oh = c.find(".comment-content").html() || "";
// jQuery trick: decode HTML to plain text
var ot = $("
").html(oh).text();
var t = c.data("commenter-name") || "";
if(t && ot.indexOf("@" + t) === 0) {
ot = ot.substring(("@" + t).length).trim();
}
var sv = parseFloat(c.data("star") || 0);
var isSec = !!c.data("secret");
c.empty();
var f = '';
f += '
';
c.append(f);
var fm = c.find(".inline-edit-form");
if(sv > 0){
fm.find("#wr_star").val(sv);
var st = fm.find(".starpoint_box .fa-star");
st.each(function(i){
if((i+1) <= sv) $(this).addClass("active");
});
fm.find("#star-rating-block, .user-info, .reply-buttons, .btn-cancel, .btn-reply").removeClass("d-none");
fm.find(".btn-reply").prop("disabled", false).text("수정");
} else {
fm.find("#star-rating-block, .user-info, .reply-buttons, .btn-cancel, .btn-reply").removeClass("d-none");
fm.find(".btn-reply").prop("disabled", false).text("수정");
}
if(isSec){
fm.find(".secret-check").removeClass("d-none");
fm.find("#wr_secret_inline").prop("checked", true);
} else {
fm.find(".secret-check").removeClass("d-none");
}
fm.find(".starpoint_box .fa-star").on("click", function(){
var v = $(this).data("value");
fm.find("#wr_star").val(v);
fm.find(".fa-star").removeClass("active").each(function(i){
if((i+1) <= v) $(this).addClass("active");
});
});
fm.find(".btn-cancel").on("click", function(e){
e.preventDefault();
$("#comment_" + cid).replaceWith(originalOuterHTML);
currentEditId = null;
});
fm.on("input", "input[name='wr_content']", function(){
var v = $(this).val().trim();
fm.find(".btn-reply").prop("disabled", v.length < 1);
});
fm.on("submit", function(e){
e.preventDefault();
$.ajax({
url: fm.attr("action"),
type: "POST",
data: fm.serialize(),
dataType: "json",
success: function(r){
if(r.success){
var cid = fm.find("input[name='comment_id']").val();
$("#comment_" + cid).replaceWith(r.comment_html);
if(typeof updateRatingSummary === "function") updateRatingSummary();
currentEditId = null;
}
}
});
});
});
$(document).off("click", ".comment-like-btn:not(.child-like)").on("click", ".comment-like-btn:not(.child-like)", function(e){
e.preventDefault();
var cid = $(this).data("id");
if(!cid)return;
var b = $(this);
var l = b.find("span");
var db = b.closest("ul,.bo_vc_act").find(".comment-dislike-btn:not(.child-like)").find("span");
$.ajax({
url: (typeof AJAX_COMMENT_ACTION_URL !== "undefined") ? AJAX_COMMENT_ACTION_URL : "/comment/comment_action.php",
type: "POST",
dataType: "json",
data: {
action: "vote",
bo_table: (typeof BO_TABLE !== "undefined") ? BO_TABLE : "",
comment_id: cid,
vote_type: "good"
},
success: function(res){
if(res.success){
var ng = res.good_count || 0, nog = res.nogood_count || 0;
l.text(ng);
db.text(nog);
b.find("i").removeClass("hand_up hand_up-2").addClass(res.new_vote_type==="good" ? "hand_up-2" : "hand_up");
b.closest("ul,.bo_vc_act").find(".comment-dislike-btn:not(.child-like) i")
.removeClass("hand_down hand_down-2")
.addClass(res.new_vote_type==="nogood" ? "hand_down-2" : "hand_down");
}
}
});
});
$(document).off("click", ".comment-dislike-btn:not(.child-like)").on("click", ".comment-dislike-btn:not(.child-like)", function(e){
e.preventDefault();
var cid = $(this).data("id");
if(!cid)return;
var b = $(this);
var lb = b.closest("ul,.bo_vc_act").find(".comment-like-btn:not(.child-like)").find("span");
var db = b.find("span");
$.ajax({
url: (typeof AJAX_COMMENT_ACTION_URL !== "undefined") ? AJAX_COMMENT_ACTION_URL : "/comment/comment_action.php",
type: "POST",
dataType: "json",
data: {
action: "vote",
bo_table: (typeof BO_TABLE !== "undefined") ? BO_TABLE : "",
comment_id: cid,
vote_type: "nogood"
},
success: function(res){
if(res.success){
var ng = res.good_count || 0, nog = res.nogood_count || 0;
lb.text(ng);
db.text(nog);
b.closest("ul,.bo_vc_act").find(".comment-like-btn:not(.child-like) i")
.removeClass("hand_up hand_up-2")
.addClass(res.new_vote_type==="good" ? "hand_up-2" : "hand_up");
b.find("i").removeClass("hand_down hand_down-2")
.addClass(res.new_vote_type==="nogood" ? "hand_down-2" : "hand_down");
}
}
});
});
$(document).off("click", ".comment-pin-btn").on("click", ".comment-pin-btn", function(e){
e.preventDefault();
if(!window.IS_ADMIN && !(window.POST_AUTHOR_ID === window.CURRENT_USER_ID)){
alert("권한이 없습니다.");
return;
}
var cid = $(this).data("id");
var p = $(this).data("pin");
var act = (p == 1) ? "unpin" : "pin";
var btn = $(this);
$.ajax({
url: (typeof AJAX_COMMENT_ACTION_URL !== "undefined") ? AJAX_COMMENT_ACTION_URL : "/comment/comment_action.php",
type: "POST",
dataType: "json",
data: {
token: (typeof CSRF_TOKEN !== "undefined") ? CSRF_TOKEN : "",
action: act,
bo_table: (typeof BO_TABLE !== "undefined") ? BO_TABLE : "",
comment_id: cid
},
success: function(r){
if(r.success){
window.loadComments((typeof WR_ID !== "undefined" ? WR_ID : 0), "");
} else {
alert(r.message);
}
},
error: function(){
alert("서버 통신 오류");
}
});
});
$(document).off("click", ".reply-btn").on("click", ".reply-btn", function(e){
e.preventDefault();
if(!$(e.target).closest(".more-replies").length){
e.stopPropagation();
}
var btn = $(this);
var commentItem = btn.closest(".comment-item");
if(window.currentOpenFormType==="parent" && typeof resetParentCommentForm==="function"){
resetParentCommentForm($("#parent-comment-form"));
window.currentOpenFormType = null;
}
if(window.currentOpenFormType==="reply"){
var ex = $(".reply-form-container");
if(ex.length) ex.remove();
window.currentOpenFormType = null;
}
currentEditId = null;
window.currentOpenFormType = "reply";
if(commentItem.find(".reply-form-container").length) return;
var replyContainer = $('
');
btn.closest(".d-flex").after(replyContainer);
var commenterName = commentItem.data("commenter-name") || "";
var rf = '';
rf += '';
replyContainer.html(rf);
var replyForm = replyContainer.find("form");
replyForm.find("input[name='wr_content']").on("input", function(){
var v = $(this).val().trim();
replyForm.find(".btn-reply").prop("disabled", (v.length < 1));
});
replyForm.find(".btn-cancel").on("click", function(e){
e.preventDefault();
replyContainer.remove();
window.currentOpenFormType = null;
});
replyForm.on("submit", function(e) {
e.preventDefault();
if ($(this).data("submitted")) return;
$(this).data("submitted", true);
var bs = $(this).find("button[type='submit']");
bs.prop("disabled", true);
var fd = $(this).serialize();
$.ajax({
url: $(this).attr("action"),
type: "POST",
data: fd,
dataType: "json",
success: function(r) {
if (r.success) {
if (r.total_comments !== undefined) {
$("#total-comments").text(r.total_comments);
} else {
var x = parseInt($("#total-comments").text(), 10) || 0;
$("#total-comments").text(x + 1);
}
var pid = commentItem.data("comment-id");
replyForm.closest(".reply-form-container").remove();
window.currentOpenFormType = null;
window.loadRepliesAndOpen(pid, 1, function() {
var nr = $("#new_replies_" + pid);
if (!nr.length) {
nr = $('
');
$("#replies_" + pid).prepend(nr);
}
var newElem = $(r.reply_html);
var newId = newElem.attr("id");
if ($("#" + newId).length) {
$("#" + newId).remove();
}
nr.prepend(newElem);
var replyCountLink = commentItem.find(".reply-count-link");
if (replyCountLink.length) {
var currentText = replyCountLink.text();
var match = currentText.match(/\d+/);
var count = match ? parseInt(match[0], 10) + 1 : 1;
replyCountLink.html('
답글 ' + count + '개');
if (count > 0) {
commentItem.find(".replybt").removeClass("d-none");
} else {
commentItem.find(".replybt").addClass("d-none");
}
} else {
commentItem.find(".replybt").remove();
commentItem.append('
');
}
$("html, body").animate({ scrollTop: commentItem.offset().top }, 0);
$("#replies_" + pid).removeClass("d-none").show();
});
}
},
complete: function() {
replyForm.data("submitted", false);
bs.prop("disabled", false);
}
});
});
});
$(document).off("submit", "#parent-comment-form").on("submit", "#parent-comment-form", function(e){
e.preventDefault();
var f = $(this);
if(f.data("submitted")) return;
f.data("submitted", true);
var b = f.find("button[type='submit']");
b.prop("disabled", true);
var d = f.serialize();
$.ajax({
url: f.attr("action"),
type: "POST",
data: d,
dataType: "json",
success: function(r){
if(r.success){
var nch = r.comment_html;
var nco = $(nch);
var cl = $("#comment-list");
var pd = cl.find("li.comment-item[data-pinned='1']");
if(pd.length){
pd.last().after(nco);
} else {
var firstComment = cl.find("li.comment-item").first();
if(firstComment.length){
firstComment.before(nco);
} else {
cl.append(nco);
}
}
nco.find(".comment-date").each(function(){
var rawText = $(this).text();
var match = rawText.match(/(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/);
if(match){
var relative = timeAgo(match[1]);
$(this).html('
' + relative);
}
});
f[0].reset();
if(typeof updateRatingSummary === "function") updateRatingSummary();
window.currentOpenFormType = null;
}
},
complete: function(){
f.data("submitted", false);
b.prop("disabled", false);
}
});
});
$(window).off("scroll.commentInfinite").on("scroll.commentInfinite", function(){
if(window.isLoading || !window.hasMore) return;
var cnt = $("#comment-list li.comment-item").length;
if(cnt < 10) return;
var st = $(this).scrollTop(), wh = $(this).height(), dh = $(document).height();
if(st + wh >= dh - 200) loadMoreParentComments();
});
function loadMoreParentComments(){
if(window.isLoading) return;
window.isLoading = true;
if(!$("#infinite-scroll-spinner").length){
$("body").append('
');
}
$("#infinite-scroll-spinner").show();
var np = window.currentPage + 1;
$.ajax({
url: (typeof AJAX_COMMENT_LIST_URL !== "undefined") ? AJAX_COMMENT_LIST_URL : "/comment/ajax_comment_list.php",
type: "GET",
data: {
bo_table: (typeof BO_TABLE !== "undefined") ? BO_TABLE : "",
wr_id: (typeof WR_ID !== "undefined") ? WR_ID : 0,
sort: "",
page: np
},
dataType: "html",
success: function(r){
var tmp = $("
").html(r);
var nl = tmp.find("#comment-list>li.comment-item").filter(function(){
return !$("#" + $(this).attr("id")).length;
});
if(nl.length){
$("#comment-list").append(nl);
if(nl.length < 10) window.hasMore = false;
} else {
window.hasMore = false;
}
var z = tmp.find("#total-comments").text();
if(z && parseInt(z) > 0) $("#total-comments").text(z);
window.currentPage = np;
},
complete: function(){
window.isLoading = false;
$("#infinite-scroll-spinner").hide();
}
});
}
window.loadComments = function(wrId, sortType){
if(currentEditId){
$("#comment_" + currentEditId).replaceWith(originalOuterHTML);
currentEditId = null;
}
wrId = (wrId !== undefined) ? wrId : ((typeof WR_ID !== "undefined") ? WR_ID : 0);
sortType = "";
$.ajax({
url: (typeof COMMENT_LIST_URL !== "undefined") ? COMMENT_LIST_URL : "/comment/comment_list.php",
type: "GET",
data: {
bo_table: (typeof BO_TABLE !== "undefined") ? BO_TABLE : "",
wr_id: wrId,
sort: sortType
},
dataType: "html",
success: function(d){
var r = $(d).filter("#comment-list");
if(r.length) $("#comment-list").html(r.html());
else $("#comment-list").empty();
var c = $(d).find("#total-comments").text();
if(c) $("#total-comments").text(c);
var tc = parseInt(c, 10) || 0, lc = $("#comment-list li.comment-item").length;
window.hasMore = (tc > lc);
window.currentPage = 1;
}
});
};
$(document).on("show.bs.dropdown", ".comment-dropdown", function(){
var dd = $(this);
var c = dd.closest(".comment-item");
var cm = c.data("commenter-id");
if(!(window.IS_ADMIN || window.POST_AUTHOR_ID === window.CURRENT_USER_ID)){
dd.find(".action-pin").remove();
}
if(cm === window.CURRENT_USER_ID){
dd.find(".action-report").remove();
}
});
if (!window.replyToggleBound) {
$(document).on("click", ".reply-count-link", function(e){
e.preventDefault();
e.stopPropagation();
var parentId = $(this).data("parent-id");
if(!parentId){
var pe = $(this).closest("[id^='comment_']");
if(pe.length){
parentId = pe.attr("id").replace("comment_","");
}
}
if(parentId && typeof window.toggleReplies === "function"){
window.toggleReplies(parentId);
}
});
window.replyToggleBound = true;
}
$(document).on("childReplyAdded", function(e, cid){
var parentReplyLink = $("#comment_" + cid).find(".reply-count-link");
if(parentReplyLink.length){
var txt = parentReplyLink.text();
var m = txt.match(/답글\s*(\d+)/);
if(m){
var cnt = parseInt(m[1],10) + 1;
parentReplyLink.html('
답글 ' + cnt + '개');
} else {
parentReplyLink.html('
답글 1개');
}
}
});
// ============================================================
// 5) AJAX로 자식 댓글을 불러오는 loadRepliesAndOpen (중복 제거 포함)
// ============================================================
window.loadRepliesAndOpen = function(cid, page, cb, newId, newHtml){
var c = $("#comment_" + cid),
r = $("#replies_" + cid);
if(!c.length){
if(typeof cb === "function") cb();
return;
}
if(!r.length){
r = $('
');
c.append(r);
}
var rl = $("#reply_list_" + cid);
if(!rl.length){
rl = $('
');
r.append(rl);
}
if(page === 1 && rl.is(":empty")){
rl.html("
");
} else {
rl.find("#temp-spinner").remove();
rl.append("
");
}
var requestUrl;
if(page > 1){
requestUrl = (typeof AJAX_COMMENT_REPLIES_URL !== "undefined")
? AJAX_COMMENT_REPLIES_URL
: "/comment/ajax_comment_replies.php";
} else {
requestUrl = (typeof COMMENT_REPLY_URL !== "undefined")
? COMMENT_REPLY_URL
: "/comment/comment_reply.php";
}
$.ajax({
url: requestUrl,
type: "GET",
data: {
bo_table: (typeof BO_TABLE !== "undefined") ? BO_TABLE : "",
comment_id: cid,
page: page,
limit: 10
},
dataType: "html",
success: function(res){
$("[data-comment-id='" + cid + "'].more-replies-container").remove();
$("[data-comment-id='" + cid + "'].more-replies").remove();
var $res = $(res);
var $replyList = $res.filter("#reply_list_" + cid);
if(!$replyList.length){
$replyList = $res.find("#reply_list_" + cid);
}
var newList = $replyList.html() || "";
rl.find("#temp-spinner").remove();
if(page === 1){
rl.html(newList);
} else {
rl.append(newList);
}
// #new_replies_ 컨테이너: 대댓글 작성은 여기서만 처리 (업데이트는 이 컨테이너에서)
var nr = $("#new_replies_" + cid);
if(!nr.length){
nr = $('
');
r.prepend(nr);
}
if(newId !== undefined && newHtml){
var $newElem = $(newHtml);
var isSecret = $newElem.data("secret"); // `data-secret`이 비밀글 여부를 나타낸다고 가정
if (isSecret) {
$newElem.find('.comment-content').html('비밀글입니다.');
}
var $existing = nr.find("li.child-comment[data-comment-id='" + newId + "']");
if($existing.length){
$existing.first().replaceWith($newElem);
$existing.not(":first").remove();
} else {
nr.prepend($newElem);
}
}
var seen = {};
$("#new_replies_" + cid + ", #reply_list_" + cid).find("li.child-comment").each(function(){
var commentId = $(this).data("comment-id");
if(seen[commentId]){
$(this).remove();
} else {
seen[commentId] = true;
}
});
// ★ 중복 제거 로직 끝 ★
var moreWrapper = $res.find(".more-replies-container");
if(moreWrapper.length){
var existingContainer = r.find(".more-replies-container[data-comment-id='" + cid + "']");
if(existingContainer.length){
existingContainer.remove();
}
r.append(moreWrapper);
} else {
var moreLink = $res.find(".more-replies");
if(moreLink.length){
var existingLink = r.find(".more-replies[data-comment-id='" + cid + "']");
if(existingLink.length){
existingLink.remove();
}
r.append(moreLink);
}
}
if(typeof cb === "function"){
cb();
}
},
error: function(){
if(typeof cb === "function") cb();
}
});
};
});
})(jQuery);