| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774 |
- $(function() {
- // 댓글입력 창 높이 자동조정
- $.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", edit: "update", reply: "reply"},
- mode: "",
- code: "",
- bid: 0,
- pid: 0,
- cid: 0,
- uid: 0,
- total: 0,
- page: 0,
- perPage: 0,
- minLength: 0,
- maxLength: 0,
- listForm: null,
- writeForm: null,
- saveHtml: null,
- saveBefore: null,
- useEditor: false,
- queryString: null,
- tinymce: null,
- // 댓글 기본설정
- init: function(config)
- {
- if(!config.hasOwnProperty("code") && !config.hasOwnProperty("bid") && !config.hasOwnProperty("pid")) {
- return false;
- }
- this.code = config.code;
- this.bid = config.bid;
- this.pid = config.pid;
- this.callback = (BASE_URL + "/board/" + String(this.code) + "/" + String(this.pid) + "/comment");
- this.listForm = document.getElementById(this.listID);
- this.writeForm = document.getElementById(this.writeID);
- // 댓글 입력창
- 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; // 댓글 입력 창 저장
- },
- // 초기화
- reset: function(form)
- {
- this.mode = "write";
- this.cid = 0;
- this.saveBefore = null;
- if (typeof form !== "undefined") {
- if(form.elements["mode"].value !== "write") {
- form.style.display = "none";
- }
- form.elements["mode"].value = "write";
- form.elements["bid"].value = "";
- form.elements["pid"].value = "";
- form.elements["cid"].value = "";
- form.elements["uid"].value = "";
- form.elements["length"].value = "0";
- form.elements["content"].value = "";
- if (form.elements.hasOwnProperty("username")) {
- form.elements["username"].value = "";
- }
- if (form.elements.hasOwnProperty("password")) {
- form.elements["password"].value = "";
- }
- if (form.elements.hasOwnProperty("is_secret")) {
- 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;
- document.getElementById("comment_" + cid).scrollIntoView();
- }
- }
- },
- // 댓글 영역 강조
- focusCommentBox: function(cid)
- {
- if (typeof cid != "undefined" && cid) {
- $("#comment_" + cid).effect("highlight", {
- 'color': '#4f4f4f'
- }, 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(!this.code && !this.bid && !this.pid) {
- return false;
- }
- 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 형식으로 뎃글목록 출력
- if(status !== "success") {
- return;
- }
- let total = this.children.total.value;
- let page = this.children.page.value;
- let perPage = this.children.per_page.value;
- document.getElementById("txtCommentRows").innerText = total;
- document.getElementById("txtPostCommentCnt").innerText = total;
- if (message) { // 알림이 있을 경우 alert
- alert(message);
- }
- Comment.total = total;
- Comment.page = page;
- Comment.perPage = perPage;
- Comment.focusCommentBox(cid);
- Comment.scrollReplyNow(cid);
- });
- },
- // 댓글 등록/수정
- submit: function(e)
- {
- e.blur();
- e.disabled = true;
- $(e.form).validate({
- onkeyup: false,
- onclick: false,
- onfocusout: false,
- rules: {
- username: {required: "#username:enabled", minlength: 2, maxlength: 10},
- password: {required: "#password:enabled", minlength: 3, maxlength: 10},
- mode: {required: true, contains: ["write", "edit", "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: function() {
- return (Comment.maxLength > 0 ? Comment.maxLength : 500)
- }
- },
- is_secret: {number: true}
- },
- messages: {
- username: {required: "이름을 입력하세요.", minlength: "이름은 두 글자 이상 입력하세요.", maxlength: "이름은 10자까지 입력 가능합니다."},
- password: {required: "비밀번호를 입력하세요.", minlength: "비밀번호는 3자 이상 입력하세요.", maxlength: "비밀번호는 10자까지 입력 가능합니다."},
- 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 formData = new FormData(form);
- let spamKeyword = Comment.filterSpamKeyword(formData.get("content")); // 금지 단어 검사
- if (spamKeyword) {
- alert("내용에 금지어 ('" + spamKeyword + "')가 포함 되어있습니다.");
- form.elements["content"].focus();
- return false;
- }
- let page;
- let mode = formData.get("mode");
- if(mode === "write") {
- formData.append("bid", Comment.bid);
- formData.append("pid", Comment.pid);
- page = Math.ceil((Number(Comment.total) + 1) / Comment.perPage);
- }else{
- page = Comment.page;
- }
- if(mode === "edit") {
- formData.append("_method", "PUT");
- }
- // 버튼 비활성화
- 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,
- contentType: false,
- processData: false,
- data: formData,
- dataType: "json",
- beforeSend: function () {
- if (formData.get("uid")) { // 권한 확인
- if (!loginCheck()) {
- return xhr.abort();
- }
- }
- showLoading();
- },
- success: function (res) {
- if (res.success) {
- Comment.list(page, res.cid);
- }else{
- alert(res.message);
- }
- },
- error: function (xhr, status, err) {
- procErrorEvent(xhr, status, err);
- },
- complete: function() {
- Comment.reset(form);
- hideLoading();
- }
- });
- }
- });
- $(e.form).submit();
- },
- // 수정, 답글
- write: function(e, mode)
- {
- e.blur();
- if(typeof e === "undefined") {
- return false;
- }
- if(typeof mode === "undefined" || mode == null || !mode) {
- return false;
- }
- if(!mode in this.method) {
- return false;
- }
- let formData = new FormData(e.form); // 댓글 영역
- let mediaFormID = ("#fCommentWrite_" + formData.get("cid")); // 현재 답글 번호
- let $saveBefore = $(this.saveBefore); // 이전 댓글 창
- let $target = $(mediaFormID); // 현재 댓글 창
- if(this.cid === formData.get("cid") && this.saveBefore === mediaFormID && this.mode === mode) {
- $saveBefore.toggle();
- }else{
- $saveBefore.html("");
- $target.show();
- let writeForm = $target.html(this.saveHtml).get(0).firstElementChild;
- // 답글
- if(mode === "reply") {
- if(writeForm.elements.hasOwnProperty("username")) {
- writeForm.elements["username"].value = "";
- }
- if(writeForm.elements.hasOwnProperty("is_secret")) {
- writeForm.elements["is_secret"].checked = false;
- }
- writeForm.elements["content"].value = "";
- }
- // 수정
- if(mode === "edit") {
- if(writeForm.elements.hasOwnProperty("username")) {
- writeForm.elements["username"].value = formData.get("username");
- }
- if(writeForm.elements.hasOwnProperty("is_secret")) {
- writeForm.elements["is_secret"].checked = Boolean(formData.get("is_secret").checked);
- }
- writeForm.elements["content"].value = formData.get("content");
- // 입력창 높이 조절
- this.resizeTextarea(writeForm.elements["content"]);
- }
- writeForm.elements["mode"].value = mode;
- writeForm.elements["bid"].value = formData.get("bid");
- writeForm.elements["pid"].value = formData.get("pid");
- writeForm.elements["cid"].value = formData.get("cid");
- writeForm.elements["uid"].value = formData.get("uid");
- // textarea ID 할당
- if(writeForm) {
- writeForm.elements["content"].setAttribute("id", formData.get("content") + "_" + formData.get("cid"));
- // 1:1 문의 게시판은 에디터를 사용
- if(this.useEditor) {
- tinyMCE.EditorManager.execCommand('mceAddEditor', true, writeForm.elements["content"]);
- }
- // 글자 수 확인
- this.checkByte(formData.get("content"));
- }
- }
- this.mode = mode;
- this.cid = formData.get("cid");
- this.saveBefore = mediaFormID; // 현재 영역
- },
- // 댓글 삭제
- delete: function(e)
- {
- e.blur();
- let formData = new FormData(e.form);
- $.ajax({
- url: (this.callback + "/delete"),
- type: "delete",
- cache: false,
- async: false,
- data: {bid: formData.get("bid"), pid: formData.get("pid"), cid: formData.get("cid"), _method: "DELETE"},
- dataType: "json",
- beforeSend: function(xhr) {
- if (!formData.get("uid")) { // 권한 확인
- const password = prompt("댓글 비밀번호 확인이 필요합니다.\n비밀번호를 입력해주세요.");
- if (!password) {
- return false;
- }
- this.url += ("?passwd=" + encodeURIComponent(password.trim()));
- } else {
- if (!loginCheck()) {
- return xhr.abort();
- }
- }
- if (!confirm("댓글을 삭제하시겠습니까?")) {
- return false;
- }
- },
- 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;
- }
- // 신고 접수 유효성 적용
- $("#fCommentBlame").validate({
- onkeyup: false,
- onclick: false,
- onfocusout: false,
- rules: {
- type: {required: true, contains: ['1', '2', '3', '4', '5', '6', '7', '8', '9']},
- reason: {
- required: true, normalizer: function (value) {
- return $.trim(value);
- }, maxlength: 1000
- }
- },
- messages: {
- type: {required: "신고 유형을 선택해주세요.", contains: "잘못된 요청입니다."},
- reason: {required: "신고 내용을 입력해주세요.", maxlength: "신고 내용은 {0}자까지 입력 가능합니다."}
- },
- showErrors: function (errorMap, errorList) {
- if (this.numberOfInvalids()) {
- alert(errorList[0].message);
- errorList[0].element.focus();
- }
- },
- submitHandler: function (form) {
- if (confirm("신고를 접수하시겠습니까?")) {
- let formData = new FormData(form);
- formData.append("bid", e.form.elements["bid"].value);
- formData.append("pid", e.form.elements["pid"].value);
- formData.append("cid", e.form.elements["cid"].value);
- $.ajax({
- url: (Comment.callback + "/blame"),
- type: "post",
- cache: false,
- contentType: false,
- processData: false,
- data: formData,
- dataType: "json",
- beforeSend: function (xhr) {
- if (!loginCheck()) {
- xhr.abort();
- }
- },
- success: function (res) {
- if (res.success) {
- alert("감사합니다. 신고가 접수되었습니다. 이용 규칙을 위반한 것으로 확인되면 댓글이 삭제됩니다.");
- } else {
- alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
- }
- },
- error: function (xhr, status, err) {
- procErrorEvent(xhr, status, err);
- },
- complete : function() {
- $("#commentBlameModal").modal('hide');
- }
- });
- }
- }
- });
- },
- // 추천
- like: function (e) {
- let formData = new FormData(e.form);
- formData.append("type", e.value);
- $.ajax({
- url: (this.callback + "/like"),
- type: "post",
- cache: false,
- contentType: false,
- processData: false,
- data: formData,
- dataType: "json",
- beforeSend: function (xhr) {
- if (!loginCheck()) {
- xhr.abort();
- }
- },
- success: function (res) {
- if (res.success) {
- Comment.toggleLike(formData.get("cid"), 1, !Number(e.dataset.active));
- } else {
- alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
- }
- },
- error: function (xhr, status, err) {
- procErrorEvent(xhr, status, err);
- }
- });
- },
- // 비추천
- dislike: function (e) {
- let formData = new FormData(e.form);
- formData.append("type", e.value);
- $.ajax({
- url: (this.callback + "/dislike"),
- type: "post",
- cache: false,
- contentType: false,
- processData: false,
- data: formData,
- dataType: "json",
- beforeSend: function (xhr) {
- if (!loginCheck()) {
- xhr.abort();
- }
- },
- success: function (res) {
- if (res.success) {
- Comment.toggleLike(formData.get("cid"), 2, !Number(e.dataset.active));
- } else {
- alert(res.message || "처리 중 오류가 발생하였습니다. 관리자에게 문의하십시오.");
- }
- },
- error: function (xhr, status, err) {
- procErrorEvent(xhr, status, err);
- }
- });
- },
- // 댓글 입력 취소
- cancel: function (e) {
- if (e.form.mode.value === "write") {
- e.form.elements["mode"].value = "write";
- e.form.elements["cid"].value = "";
- e.form.elements["length"].value = "0";
- e.form.elements["content"].value = "";
- if (typeof e.form.elements["is_secret"] !== "undefined") {
- e.form.elements["is_secret"].checked = false;
- }
- let length = e.form.getElementsByClassName("comment-length");
- if (length.length > 0) {
- length[0].innerText = "0";
- }
- } else {
- e.form.parentNode.style.display = "none";
- e.form.parentNode.innerHTML = "";
- }
- this.reset(e.form);
- },
- /*
- * 댓글 에디터 옵션 변경
- * 1:1 게시판에서 댓글을 작성하면 실행
- */
- setInitEditor: function () {
- let tinyMCEExtendSetting = {
- min_height: 210,
- max_height: 310,
- file_browser_url: (BASE_URL + "/board/" + this.code + "/uploader"),
- 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;
- });
- }
- };
- this.tinymce = 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 = '<i class="fas fa-thumbs-up"></i><span> ' + String(rows) + '</span>';
- button.dataset.active = "1";
- } else {
- rows = (rows > 0 ? rows - 1 : rows);
- button.innerHTML = '<i class="far fa-thumbs-up"></i><span> ' + String(rows) + '</span>';
- 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 = '<i class="fas fa-thumbs-down"></i><span> ' + String(rows) + '</span>';
- button.dataset.active = "1";
- } else {
- rows = (rows > 0 ? rows - 1 : rows);
- button.innerHTML = '<i class="far fa-thumbs-down"></i><span> ' + String(rows) + '</span>';
- 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-edit", function () {
- Comment.write(this, "edit");
- });
- // 댓글 취소
- $(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["type"].selectedIndex = 0;
- form.elements["reason"].value = "";
- if(!IS_USER) {
- return false;
- }
- });
|