$(function() {
Comment.init();
Comment.list();
// 댓글입력 창 높이 자동조정
$.each($('textarea[data-autoresize]'), function () {
$(this).on('keyup input', function () {
Comment.resizeTextarea(this);
}).removeAttr('data-autoresize');
});
});
const Comment =
{
callback: "",
listID: "commentList",
writeID: "commentWrite",
method: {write: "store", modify: "update", reply: "reply"},
mode: "", // write, modify, reply
code: "",
bid: 0,
pid: 0,
cid: 0,
total: 0,
page: 0,
perPage: 0,
minLength: 0,
maxLength: 0,
listForm: null,
writeForm: null,
saveHtml: null,
saveBefore: null,
useEditor: false,
// 댓글 기본설정
init: function()
{
this.listForm = document.getElementById(this.listID);
// 댓글 목록
if(this.listForm !== null) {
this.code = document.getElementById("code").value;
this.bid = document.getElementById("bid").value;
this.pid = document.getElementById("pid").value;
this.callback = (BASE_URL + "/board/" + String(this.code) + "/" + String(this.pid) + "/comment");
}
this.writeForm = document.getElementById(this.writeID);
// 댓글 입력창
if(IS_USER && this.writeForm !== null) {
let form = this.writeForm.getElementsByTagName("form")[0];
this.minLength = Number(form.elements["min_length"].value);
this.maxLength = Number(form.elements["max_length"].value);
this.saveHtml = this.writeForm.innerHTML; // 댓글 입력 창 저장
this.reset(form);
}
},
// 초기화
reset: function(form)
{
this.mode = "write";
this.cid = 0;
this.saveBefore = null;
if (typeof form !== "undefined") {
form.elements["mode"].value = "write";
form.elements["cid"].value = "";
form.elements["length"].value = "0";
form.elements["content"].value = "";
if (typeof form.elements["is_secret"] !== "undefined") {
form.elements["is_secret"].checked = false;
}
let $length = form.getElementsByClassName("comment-length");
if ($length.length > 0) {
$length[0].innerText = "0";
}
form.elements["btn_comment_submit"].disabled = false;
form.elements["btn_comment_cancel"].disabled = false;
this.resizeTextarea(form.elements["content"]);
}
if (this.useEditor) {
tinyMCE.activeEditor.setContent("");
}
},
// 댓글 목록 새로고침
refresh: function() {
this.list(this.page);
},
// textarea 높이 조절
resizeTextarea: function(e)
{
$(e).css('height', 'auto').css('height', e.scrollHeight + (e.offsetHeight - e.clientHeight));
},
// 댓글 영역으로 스크롤 이동
scrollReplyNow: function(cid)
{
if (typeof cid != "undefined" && cid) {
let offset = $('#comment_' + cid).offset();
if(typeof offset != "undefined"){
window.document.body.scrollTop = offset.top;
}
}
},
// 댓글 영역 강조
focusCommentBox: function(cid)
{
if (typeof cid != "undefined" && cid) {
$('#comment_' + cid).effect('highlight', {
'color': '#FFFFC6'
}, 1500);
}
},
// 금지 단어 확인
filterSpamKeyword: function (content)
{
let ret = "";
$.ajax({
headers: {'X-CSRF-TOKEN': CSRF},
url: (BASE_URL + '/api/filterSpamKeyword'),
type: 'POST',
dataType: 'JSON',
async: false,
cache: false,
data: {subject: "", content: content},
success: function (res) {
ret = res.content;
},
error: function (xhr, status, err) {
procErrorEvent(xhr, status, err);
}
});
return ret;
},
// 글자수 확인
checkByte: function(e)
{
let form = e.form;
if (typeof form !== "undefined") {
let hiddenInputLength = form.elements["length"];
let spanInputLength = form.getElementsByClassName("comment-length")[0];
let textarea = form.elements["content"];
let length = textarea.value.length;
let tinymce = form.getElementsByTagName("iframe");
if (this.useEditor) {
let editor = tinymce[0].contentDocument.body;
length = editor.innerText.trim().length;
if (this.maxLength > 0 && length > this.maxLength) {
editor.innerHTML = editor.innerHTML.substr(0, this.maxLength);
length = editor.innerHTML.length;
}
} else {
if (this.maxLength > 0 && length > this.maxLength) {
textarea.value = textarea.value.substr(0, this.maxLength);
length = textarea.value.length;
}
}
// 글자 수 저장
hiddenInputLength.value = length;
// 글자 수 출력
if (typeof spanInputLength !== "undefined") {
spanInputLength.innerText = length;
}
}
},
// 목록
list: function(page, cid, message, sort) {
if (!page || page < 1 || page === Number.POSITIVE_INFINITY) {
page = 1;
}
let listURL = (this.callback + "?page=" + page);
if (sort) {
listURL += "&sort=" + sort;
}
$('#' + this.listID).load(listURL, function (response, status, xhr) { // HTML 형식으로 뎃글목록 출력
let total = this.children.total.value;
let page = this.children.page.value;
let perPage = this.children.per_page.value;
if (total) { // 댓글 수 표시
document.getElementById("txtCommentRows").innerText = total;
document.getElementById("txtPostCommentCnt").innerText = total;
}
if (message) { // 알림이 있을 경우 alert
alert(message);
}
Comment.page = page;
Comment.perPage = perPage;
Comment.total = total;
Comment.focusCommentBox(cid);
Comment.scrollReplyNow(cid);
});
return false;
},
// 댓글 등록/수정
submit: function(e)
{
e.blur();
e.disabled = true;
$(e.form).validate({
onkeyup: false,
onclick: false,
onfocusout: false,
rules: {
mode: {required: true, contains: ["write", "modify", "reply"]},
content: {
required: true,
normalizer: function (value) {
if(Comment.useEditor) {
return tinyMCE.activeEditor.getContent({format: "text"}).trim();
}else{
return value.trim();
}
},
minlength: Comment.minLength,
maxlength: Comment.maxLength
},
is_secret: {number: true}
},
messages: {
mode: {required: "댓글 처리중 오류가 발생하였습니다.", contains: "잘못된 요청입니다."},
content: {required: "댓글을 입력해주세요."},
is_secret: {number: true}
},
showErrors: function (errorMap, errorList) {
if (this.numberOfInvalids()) {
setTimeout(function() {
alert(errorList[0].message);
errorList[0].element.focus();
if(Comment.useEditor) {
tinyMCE.activeEditor.getBody().scrollIntoView();
}else{
window.scrollTo({top: errorList[0].element.offsetTop});
}
}, 100);
e.disabled = false;
}
},
submitHandler: function (form)
{
let mode = form.elements["mode"].value;
let content = form.elements["content"].value;
let spamKeyword = Comment.filterSpamKeyword(content); // 금지 단어 검사
if (spamKeyword) {
alert("내용에 금지어 ('" + spamKeyword + "')가 포함 되어있습니다.");
form.elements["content"].focus();
return false;
}
// 댓글 등록
let formData = $(form).serializeArray();
formData.push({name: "bid", value: Comment.bid});
formData.push({name: "pid", value: Comment.pid});
// 버튼 비활성화
form.elements["btn_comment_submit"].disabled = true;
form.elements["btn_comment_cancel"].disabled = true;
$.ajax({
headers: {'X-CSRF-TOKEN': CSRF},
url: (Comment.callback + "/" + Comment.method[mode]),
type: 'post',
cache: false,
async: true,
data: formData,
dataType: 'json',
beforeSend: function (xhr) {
if (!loginCheck()) {
xhr.abort();
}
showLoading();
},
success: function (res) {
if (res.success) {
let page = (mode === "write" ? Math.ceil((Number(Comment.total) + 1) / Comment.perPage) : Comment.page);
Comment.list(page, res.commentID);
}else{
alert(res.message);
}
Comment.reset(form);
},
error: function (xhr, status, err) {
procErrorEvent(xhr, status, err);
},
complete: function() {
hideLoading();
}
});
}
});
$(e.form).submit();
},
// 수정, 답글
write: function(e, mode)
{
if(!loginCheck()) {
return false;
}
if(typeof e === "undefined") {
return false;
}
if(typeof mode == "undefined" || mode == null || !mode) {
return false;
}
if($.inArray(mode, ["write", "modify", "reply"]) < 0) {
return false;
}
let listForm = e.form; // 댓글 영역
let writeForm = null;
let cid = (listForm.elements["cid"].value || 0);
let mediaFormID = ("#fCommentWrite_" + cid);
let $saveBefore = $(this.saveBefore); // 이전 답글
let $target = $(mediaFormID); // 현재 답글
// 답글
if(mode === "reply") {
if(this.cid === cid && this.saveBefore === mediaFormID && this.mode === mode) {
$saveBefore.toggle(); // 기존 댓글 창 보기/숨김
}else{
$saveBefore.html("");
$target.show();
writeForm = $target.html(this.saveHtml).get(0).firstElementChild;
writeForm.elements["mode"].value = mode;
writeForm.elements["cid"].value = cid;
}
}
// 수정
if(mode === "modify") {
$saveBefore.html("");
$target.show();
writeForm = $target.html(this.saveHtml).get(0).firstElementChild;
writeForm.elements["content"].value = listForm.content.value; // 내용 대입
if(typeof writeForm.elements["is_secret"] !== "undefined") {
writeForm.elements["is_secret"].checked = Boolean(listForm.is_secret.value === '1'); // 비밀글 체크
}
writeForm.elements["mode"].value = mode;
writeForm.elements["cid"].value = cid;
// 입력창 높이 조절
this.resizeTextarea(writeForm.elements["content"]);
}
// textarea ID 할당
if(writeForm) {
writeForm.elements["content"].setAttribute("id", writeForm.elements["content"].name + "_" + cid);
// 1:1 문의 게시판은 에디터를 사용
if(this.useEditor) {
tinyMCE.init(tinyMCE.activeEditor.settings);
tinyMCE.EditorManager.execCommand('mceAddEditor', true, writeForm.elements["content"]);
}
// 글자 수 확인
this.checkByte(writeForm.elements["content"]);
}
this.mode = mode;
this.cid = cid;
this.saveBefore = mediaFormID; // 현재 영역
},
// 댓글 삭제
delete: function(e)
{
e.blur();
if (confirm("정말 삭제 하시겠습니까?")) {
let bid = e.form.bid.value;
let pid = e.form.pid.value;
let cid = e.form.cid.value;
$.ajax({
url: (this.callback + "/delete"),
type: 'delete',
cache: false,
async: false,
data: {bid: bid, pid: pid, cid: cid, _method: "delete"},
dataType: 'json',
beforeSend: function(xhr) {
if(!loginCheck()) {
xhr.abort();
}
},
success: function (res) {
if (res.success) {
alert("댓글이 삭제되었습니다.");
Comment.refresh();
}else{
alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
}
Comment.reset();
},
error: function (xhr, status, err) {
procErrorEvent(xhr, status, err);
}
});
}
return false;
},
// 댓글 신고
blame: function(e)
{
e.blur();
if(!loginCheck()) {
return false;
}
let bid = e.form.bid.value;
let pid = e.form.pid.value;
let cid = e.form.cid.value;
// 신고 접수 유효성
$("#fCommentBlame").validate({
onkeyup: false,
onclick: false,
onfocusout: false,
rules: {
blame_type: {required: true, contains: ['1', '2', '3', '4', '5', '6', '7', '8', '9']},
blame_reason: {required: true, normalizer: function (value) {return $.trim(value);}, maxlength: 1000}
},
messages: {
blame_type: {required: "신고 유형을 선택해주세요.", contains: "잘못된 요청입니다."},
blame_reason: {required: "신고 내용을 입력해주세요.", maxlength: "신고 내용은 {0}자까지 입력 가능합니다."}
},
showErrors: function (errorMap, errorList) {
if (this.numberOfInvalids()) {
alert(errorList[0].message);
errorList[0].element.focus();
}
},
submitHandler: function(form) {
if (confirm("신고를 접수하시겠습니까?")) {
$.ajax({
url: (this.callback + "/blame"),
type: 'post',
cache: false,
async: false,
data: {bid: bid, pid: pid, cid: cid, type: form.blame_type.value, reason: form.blame_reason.value},
dataType: 'json',
beforeSend: function (xhr) {
if(!loginCheck()) {
xhr.abort();
}
},
success: function (res) {
form.blame_type.value = "";
form.blame_reason.value = "";
if (res.success) {
alert("감사합니다. 신고가 접수되었습니다. 이용 규칙을 위반한 것으로 확인되면 댓글이 삭제됩니다.");
}else{
alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
}
$('div.modal').modal('hide');
},
error: function (xhr, status, err) {
procErrorEvent(xhr, status, err);
}
});
}
}
});
},
// 추천
like: function (e) {
let bid = e.form.bid.value;
let pid = e.form.pid.value;
let cid = e.form.cid.value;
let type = e.value;
let active = Number(e.dataset.active);
$.ajax({
url: (this.callback + "/like"),
type: 'post',
cache: false,
async: false,
data: {bid: bid, pid: pid, cid: cid, type: type},
dataType: 'json',
beforeSend: function (xhr) {
if (!loginCheck()) {
xhr.abort();
}
},
success: function (res) {
if (res.success) {
Comment.toggleLike(cid, 1, !active);
} else {
alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
}
},
error: function (xhr, status, err) {
procErrorEvent(xhr, status, err);
}
});
},
// 비추천
dislike: function (e) {
let bid = e.form.bid.value;
let pid = e.form.pid.value;
let cid = e.form.cid.value;
let type = e.value;
let active = Number(e.dataset.active);
$.ajax({
url: (this.callback + "/dislike"),
type: 'post',
cache: false,
async: false,
data: {bid: bid, pid: pid, cid: cid, type: type},
dataType: 'json',
beforeSend: function (xhr) {
if (!loginCheck()) {
xhr.abort();
}
},
success: function (res) {
if (res.success) {
Comment.toggleLike(cid, 2, !active);
} else {
alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
}
},
error: function (xhr, status, err) {
procErrorEvent(xhr, status, err);
}
});
},
// 댓글 입력 취소
cancel: function ($this) {
if ($this.form.mode.value === "write") {
$this.form.elements["mode"].value = "write";
$this.form.elements["cid"].value = "";
$this.form.elements["length"].value = "0";
$this.form.elements["content"].value = "";
if (typeof $this.form.elements["is_secret"] !== "undefined") {
$this.form.elements["is_secret"].checked = false;
}
let $length = $this.form.getElementsByClassName("comment-length");
if ($length.length > 0) {
$length[0].innerText = "0";
}
} else {
$this.form.parentNode.style.display = "none";
$this.form.parentNode.innerHTML = "";
}
this.reset($this.form);
},
/*
* 댓글 에디터 옵션 변경
* 1:1 게시판에서 댓글을 작성하면 실행
*/
setInitEditor: function () {
let tinyMCEExtendSetting = {
min_height: 210,
max_height: 310,
init_instance_callback: function (editor) {
editor.on('SetContent', function (e) {
let iframeRows = e.target.contentDocument.body.getElementsByTagName("iframe");
if (iframeRows > 0) {
$(e.content).filter("iframe").attr("src", ""); // iframe src 주소
}
});
editor.on('keyup', function () {
Comment.checkByte(editor.targetElm);
});
editor.on('keypress', function () {
Comment.checkByte(editor.targetElm);
// document.getElementById(e.target.dataset.id).value = e.currentTarget.textContent;
});
}
};
tinymce.init(Object.assign(tinyMCE.activeEditor.settings, tinyMCEExtendSetting));
this.useEditor = true;
},
// 좋아요/싫어요 처리
toggleLike: function (cid, type, active) {
let btnCommentLike = document.getElementById("comment_" + cid).getElementsByClassName("btn-comment-like")[0];
let btnCommentDisLike = document.getElementById("comment_" + cid).getElementsByClassName("btn-comment-dislike")[0];
if (type === 1) {
this.setLike(cid, active);
if (Number(btnCommentDisLike.dataset.active)) {
this.setDislike(cid, false);
}
} else if (type === 2) {
this.setDislike(cid, active);
if (Number(btnCommentLike.dataset.active)) {
this.setLike(cid, false);
}
}
},
// 좋아요 갱신
setLike: function (cid, active) {
let button = document.getElementById("comment_" + cid).getElementsByClassName("btn-comment-like")[0];
let rows = Number(button.dataset.rows);
if (active) {
rows = (rows + 1);
button.innerHTML = ' ' + String(rows) + '';
button.dataset.active = "1";
} else {
rows = (rows > 0 ? rows - 1 : rows);
button.innerHTML = ' ' + String(rows) + '';
button.dataset.active = "0";
}
button.dataset.rows = rows;
},
// 싫어요 갱신
setDislike: function (cid, active) {
let button = document.getElementById("comment_" + cid).getElementsByClassName("btn-comment-dislike")[0];
let rows = Number(button.dataset.rows);
if (active) {
rows = (rows + 1);
button.innerHTML = ' ' + String(rows) + '';
button.dataset.active = "1";
} else {
rows = (rows > 0 ? rows - 1 : rows);
button.innerHTML = ' ' + String(rows) + '';
button.dataset.active = "0";
}
button.dataset.rows = rows;
}
};
// 댓글 입력하면 창 크기 조절
$(document).on("keyup input", "textarea[data-autoresize]", function() {
Comment.resizeTextarea(this);
});
// 댓글 글자수 확인
$(document).on('keydown keyup', "textarea.comment-content", function (e) {
Comment.checkByte(this);
});
// 댓글 등록
$(document).on("click", "button.btn-comment-submit", function () {
Comment.submit(this);
});
// 댓글 답글
$(document).on("click", "button.btn-comment-reply", function() {
Comment.write(this, "reply");
});
// 댓글 수정
$(document).on("click", "button.btn-comment-modify", function () {
Comment.write(this, "modify");
});
// 댓글 취소
$(document).on("click", "button.btn-comment-cancel", function () {
Comment.cancel(this);
});
// 댓글 삭제
$(document).on("click", "button.btn-comment-delete", function () {
Comment.delete(this);
});
// 댓글 신고
$(document).on("click", "button.btn-comment-blame", function() {
Comment.blame(this);
});
// 댓글 추천하기
$(document).on("click", "button.btn-comment-like", function () {
Comment.like(this);
});
// 댓글 비추천하기
$(document).on("click", "button.btn-comment-dislike", function () {
Comment.dislike(this);
});
// 댓글 페이징 처리
$(document).on("click", "#commentList > nav > ul > li > a", function () {
let page = Number(params('page', this.href));
return Comment.list(page);
});
// 댓글 정렬
$(document).on("change", "select#commentSort", function () {
Comment.list(null, null, null, this.value);
});
// 댓글 신고 모달 열리면 초기화
$(document).on("show.bs.modal", "#commentBlameModal", function(e) {
let form = e.currentTarget.getElementsByTagName("form")[0];
form.elements["blame_type"].selectedIndex = 0;
form.elements["blame_reason"].value = "";
});