작성자 : 윤삼
출처 : XE타운 > 질문/공유 > 팁 게시판

https://xetown.com/tips/1710333

샘플페이지 : https://dev.aporia.blog/board_zjsF61/44317



스케치북 스킨 기반에서 대댓글을 textarea가 아니라 위지윅에디터로 바로 작성할 수 있는 팁입니다.

... 새로고침 없는 대댓글 작성까지는 아니고 그냥 현재 페이지에서 에디터를 불러오는 방식입니다.

... ck에디터로만 작업을 해봤으니 다른 에디터로도 될지는 잘 모르겠네요

 

그동안 대댓글 작성은 페이지 이동을 해서 따로 에디터를 불러와 작성하거나, 스케치북처럼 댓글 목록 하단에 textarea를 불러와서 간단하게 작성하는 게 보통이었습니다.

... 이곳 타운의 대댓글 방식이 바로 그렇죠. 유저들에게 에디터 선택을 하게 해준다고 하는데 에디터를 선택하면 새 창으로 넘어가버립니다.

... 구글링해보니 다른 곳에서는 이런 민원도 있었네요. https://www.newri.net/newri_issue/122954

 

이하의 팁은 스케치북 스킨을 기반으로 작성한 것이며, 에디터 호출 방식이 position 속성을 통해 좌표값으로 위치를 이동시키는 방식이어서 다분히 매뉴얼하다는 점 미리 안내해드립니다. (즉, 엄청난 모험일 수 있으니 백업 꼭 하세요)

... 에디터를 absolute 포지션으로 두는 것은 에디터 스킨에 있는 인라인 스크립트 때문인데요. 암튼 이와 관련된 속사정은 다음 문서의 댓글 대화를 참고해두시면 좋겠습니다. https://xetown.com/topics/1710052#comment

 

 

 

0. _comment.html 확인

- 이거는 그냥 확인차 남기는 기록입니다. (아시는 분은 그냥 패스)

- 대댓글 에디터를 여는 동작은 각 댓글의 메뉴에 있지요. 이 부분이에요. https://github.com/rhymix/rhymix-sketchbook/blob/f137bb37f24160e35501bd9f03973e9679a89e8c/_comment.html#L72

- 스케치북 기준으로는 고칠 필요가 없지만, 다른 스킨에서는 이렇게 대댓글폼을 여는 동작이 선행해야 한다는 사실을 염두에 두셔야 합니다.

 

1. _comment_write.html 수정

- https://github.com/rhymix/rhymix-sketchbook/blob/f137bb37f24160e35501bd9f03973e9679a89e8c/_comment_write.html#L69-L118

- 이런 부분이 있는데요. 여기가 바로 대댓글 입력폼입니다. 이 부분을 잘라내기(Ctrl + x) 해둡니다.

 

 

2. _comment_re_write.html 생성

- 빈 파일을 만들어 위에서 잘라낸 부분을 붙여넣기 하고 _comment_re_write.html라는 이름으로 파일을 생성합니다.

- 파일의 위치는 _comment_write.html과 같은 위치면 됩니다.

 

 

3. _comment_re_write.html 수정

- 새로 만들었던 파일을 수정합니다. 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--@if($grant->write_comment && $oDocument->isEnableComment())-->
<!--// 대댓글 -->
<div cond="$rd_idx==0" id="re_cmt">
    <label for="editor_2" class="cmt_editor_tl fl"><i class="fa fa-share fa-flip-vertical re"></i><strong>{$lang->write_comment}</strong></label>
    <div class="editor_select fr">
        <a class="close" href="#" onclick="jQuery('#re_cmt').fadeOut(); jQuery('#comment_'+jQuery('#re_cmt').find('[name=parent_srl]').val()).find('.dummy_for_re_cmt').fadeOut(); jQuery('#comment_'+jQuery('#re_cmt').find('[name=parent_srl]').val()).find('.re_comment').focus();return false"><i class="fa fa-times"></i> {$lang->cmd_close}</a>
    </div>
    <form action="/" method="post" onsubmit="return procFilter(this,insert_comment)" class="bd_wrt clear">
        <input type="hidden" name="mid" value="{$mid}" />
        <input type="hidden" name="document_srl" value="{$oDocument->document_srl}" />
        <input type="hidden" name="comment_srl" value="" />
        <input type="hidden" name="parent_srl" value="" />
        <input type="hidden" name="use_html" value="Y" />
        <div class="simple_wrt">
            <input type="hidden" id="htm_2" value="n" />
            <textarea id="editor_2" cols="50" rows="8" name="content" style="display: none;"></textarea>
            {$oDocument->getCommentEditor()}
        </div>
        <div class="edit_opt" cond="!$is_logged">
             ...(중략)...
    </form>
</div>
<!--@end-->

 

- 맨 위와 맨 아래에 조건문을 넣어봤습니다. 대댓글 권한 체크입니다.

- 기존 코드와 비교하면 에디터 선택 버튼이 제거됐고, 닫기 버튼의 onclick 속성값이 대폭 수정됐으며

- 원래 있던 input[name=content]를 제거한 대신, textarea에 name=content 속성을 부여했으며 동시에 hidden 처리했습니다.

- 그리고 textarea 대신 {$oDocument->getCommentEditor()} 로 모듈 관리 페이지의 추가 설정 > 위지윅 에디터에서 설정한 에디터를 가져오게 했습니다.

 

 

4. _read.html 수정

- 위에서 만든 파일은 _read.html에서 include할 겁니다.

- 위치는 https://github.com/rhymix/rhymix-sketchbook/blob/f137bb37f24160e35501bd9f03973e9679a89e8c/_read.html#L384 입니다.

- 아래와 같이 수정합니다.

1
<div id="cmtPosition" aria-live="polite"><include target="_comment.html" /><include target="_comment_re_write.html" /></div>

- 이것은 대댓글 폼이 id cmtPosition 안에 추가(append)된다는 것을 의미합니다.

- 그리고 스케치북 스킨에서는 cmtPosition보다 상위요소인 .fdb_lst 요소에 clear라는 클래스가 포함되어 있는데 여기에 position: relative가 걸려 있습니다.- 우리는 나중에 js에서 대댓글 입력폼에 absolute position을 줘서 .fdb_lst에 따라 디스플레이하게 될 겁니다. (귀찮으시죠? 포기하시는 게 나을지도... 쿨럭)

 

 

5. board.js - 함수 수정

- https://github.com/rhymix/rhymix-sketchbook/blob/f137bb37f24160e35501bd9f03973e9679a89e8c/js/board.js#L514-L522

- 여기를 보면 reComment 함수가 있는데 이걸 다음과 같이 바꿔줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function reComment(doc_srl,cmt_srl,edit_url){
    var block = $('.fdb_lst');
    var li = $('#comment_'+cmt_srl);
    var rmt = jQuery('#re_cmt').eq(0);
 
    if ( block.find('.dummy_for_re_cmt').length ) {
        block.find('.dummy_for_re_cmt').remove();
    }
 
    rmt.find('input[name=error_return_url]').val('/'+doc_srl);
    rmt.find('input[name=mid]').val(current_mid);
    rmt.find('input[name=document_srl]').val(doc_srl);
    rmt.find('input[name=parent_srl]').val(cmt_srl);
    rmt.find('textarea[id=editor_2]').hide();
 
    setReCommentPosition(block, li, rmt);
 
    if ( !li.find('.dummy_for_re_cmt').length ) {
        var dummy = '<div class="dummy_for_re_cmt"></div>';
        $(dummy).css({'height': rmt.outerHeight() + parseInt(li.css('padding-bottom')) * 3}).appendTo(li);
    }
    rmt.hide().fadeIn();
}

- 대강 이런 식의 동작입니다.

  1. 댓글 목록에서 대댓글 달기 링크를 클릭해서 들어오면 mid, document_srl, parent_srl 등을 지정해줍니다. 특히 parent_srl은 onclick 속성을 통해 들어온 인자를 통해 삽입됩니다. 즉, 대댓글을 달다가도 다른 부모댓글로 가서 댓글 달기 버튼을 누르면 parent_srl이 해당 부모댓글의 comment_srl로 바뀌는 거죠.
  2. 그리고 대댓글 폼의 위치를 설정하는 함수를 실행합니다.
  3. 아래 6번 항목에서 보겠지만 대댓글폼이 absolute position이 될 것이기 때문에 각 댓글 항목 아래에 .dummy_for_re_cmt라는 더미 요소를 추가해주고, 대댓글폼의 높이만큼 넉넉히 빈공간을 확보해둡니다. 우리의 대댓글 에디터는 기존 스케치북 스킨처럼 부모댓글 아래에 삽입되는 것이 아니라 부모댓글 위치에 레이어로 올라가는 형식입니다. (왜 이렇게 복잡하게 해야 하냐 물으신다면, 에디터 스킨 자체의 인라인 스크립트가.... ㅜ)
  4. 마지막에는 위치가 확정된 대댓글 입력폼을 페이드인 시켜서 나타나게 합니다.

- 자, 대댓글 폼의 위치를 지정해주는 setReCommentPosition이라는 함수를 실행하게 헸으니 해당 함수도 추가해줘야겠지요?

 

6. board.js - 함수 추가

- 아래와 같은 코드의 함수를 reComment 함수의 위나 아래쯤에 추가해줍니다. 코드는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function setReCommentPosition(block, li, rmt) {
    var block_top_gap = parseInt(block.css('border-top')) + parseInt(block.css('padding-top')),
        block_right_gap = parseInt(block.css('border-right')) + parseInt(block.css('padding-right'));
 
    var li_top = li.position().top,
        li_bottom = li_top + li.outerHeight(),
        li_left = parseInt(li.css('margin-left')) + parseInt(li.css('border-left')) + parseInt(li.css('padding-left')),
        li_right = parseInt(li.css('margin-right')) + parseInt(li.css('border-right')) + parseInt(li.css('padding-right')),
        li_width = li.width();
 
    rmt.css({
        'position''absolute',
        'top': block_top_gap + li_bottom,
        'right': block_right_gap + li_right,
        'width': li_width
    });
 
    if ( li.find('.dummy_for_re_cmt').length ) {
        rmt.css({
            'top': block_top_gap + li_bottom - li.find('.dummy_for_re_cmt').height()
        });
    }
}

 

- 대강 설명하면 다음과 같습니다. .fdb_lst 요소 그리고 대댓글의 타겟이 되는 부모댓글의 요소 등의 위치값과 넓이를 계산해서 대댓글폼의 위치와 넓이를 확정시켜주는 겁니다.

- 스케치북에서는 댓글 리스트의 오른쪽을 기준으로 댓글들의 depth에 따라 좌측 여백이 가변적이므로, top값, right값, width값만 있으면 부모댓글 바로 아래에 대댓글폼을 show할 수 있지요. 이 위치값은 스킨마다 다를 수 있기 때문에 개발자의 맞춤형 노가다가 필요합...

- 끝으로 18~22행에 알쏭달쏭한 코드가 보일 텐데요. 이거는 부모댓글 리스트 중에 위의 6번 과정에서 만들어뒀던 더미 요소에 관한 것입니다. 이거는 평상시에는 별 의미가 없는 코드인데요. 왜냐면 이 함수는 더미요소를 삽입하기 이전에 실행되는 함수이기 때문이에요. 즉, 앞선 5번의 함수를 보면 지금의 setReCommentPosition 함수 실행 전에 더미요소를 제거했던 것을 알 수 있죠. 그럼 언제 이 코드가 작동하느냐? 그건 바로 윈도우가 resize 될 때입니다. 에디터가 보이는 상황에서 윈도우 resize가 일어나면 에디터는 absolute 포지션을 갖기 때문에 뭔가 붕떠버리는 상황이 발생할 수밖에 없습니다. 이때 resize 이벤트로 대댓글폼을 대응하도록 만들어서 마치 반응형 에디터인 것처럼 보이게 할 겁니다.

 

 

7. board.js - 동작 추가

- 이제 마지막입니다. 마지막일 걸요...?

- https://github.com/rhymix/rhymix-sketchbook/blob/f137bb37f24160e35501bd9f03973e9679a89e8c/js/board.js#L473-L474 여기 473행과 474행 사이쯤에 아래와 같은 코드를 추가해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Recomment Editor Resize
var re_cmt = $('#re_cmt');
$(window).on('resize'function() {
    if ( re_cmt.is(':hidden') ) {
        return;
    }
    var block = $('.fdb_lst');
    var cmt_srl = re_cmt.find('[name="parent_srl"]').val();
    var li = $('#comment_'+cmt_srl);
    setReCommentPosition(block, li, re_cmt);
});
var observer = new ResizeObserver(entries => {
    for (let entry of entries) {
        var target_srl = re_cmt.find('[name="parent_srl"]').val();
        var target = $('#comment_' + target_srl);
        var dummy = target.find('.dummy_for_re_cmt');
        if ( dummy.length ) {
            dummy.css({height: re_cmt.outerHeight() + parseInt(target.css('padding-bottom')) * 3});
        }
    }
});
observer.observe(re_cmt[0]);

- 이게 바로 에디터 리사이즈와 관련된 동작 코드입니다.

- 윈도우가 라사이즈될 때, 대댓글폼이 visible 상태라면, 대댓글폼의 위치값을 다시 구해서 스타일로 반영합니다.

- 그리고 에디터 안에서 도구상자를 여닫는다는가, 파일 첨부를 해서 파일리스트로 인해 에디터 높이가 달라진다면 거기에 맞춰 부모댓글의 더미요소의 높이도 똑같이 대응하도록 해주는 거죠.

- 이렇게 하면 대댓글 에디터 달기 프로젝트는 어느 정도 완성된 거라 보시면 되겠습니다. (빼먹은 거 없겠죠? ㄷㄷㄷㄷ)

 

 

작업한 과정을 기억나는대로 찾아서 코드를 소개하긴 했는데요. 빼먹은 부분이 있을 수 있습니다.

그나저나 퇴고하는 차원에서 글을 다시 보는데 이걸 누가 따라하나 싶네요ㅜㅜㅜㅜ


윤삼님 팁을 따라하던 중에 빠진 부분이 있는거 같아 추가합니다.


작업시 주의사항1) 인클루드한 대댓글 html 문서는 감추기

<div cond="$rd_idx==0" id="re_cmt" style="display:none;">
..(중략)..
</div>

처음부터 펼쳐져있길래 해당 부분은 display:none; 속성을 추가해줬습니다.


작업시 주의사항2) 인클루드할 부분의 id는 comPosition 이어야 합니다.

<section class="vbo_vcmt vbo_vcmt_chat comment-media" cond="$oDocument->variables['comment_count']"  id="cmtPosition"> <!--id="vcmt_anchor"-->
  <include target="_comment.html"/>
  <include target="reply.html" />
</section>

작업시 주의사항3) 루프문으로 돌아가는 코멘트 출력 요소의 클래스는 fdb_lst 가 있어야 합니다.

<!--@foreach($oDocument->getComments() as $key => $comment)-->
<article class="fdb_lst vcmt ..(중략)..
</article>
<!--@end-->

저 같은 경우는 별도의 코멘트 페이지를 만들었었는데 여기에 fdb_lst 클래스가 추가되어야 위 팁이 정상적으로 동작하게 됩니다.


추가수정1. 중복 ID 삭제하기

modules/board/skins/스킨명/_comment_write.html

기존 _comment_write.html 파일에 보시면 

<div cond="$rd_idx==0" id="re_cmt">
..(중략)..
</div>

이 부분은 삭제해야 정상적으로 로드됩니다. 동일한 id값을 가진 요소가 있으므로 정상적으로 대댓글이 나타나지 않습니다.


추가수정2. 페이지 이동 없이 댓글 삭제하기

윤삼님 샘플 게시판을 보면 삭제, 수정도 페이지 이동없이 이뤄집니다만 이 팁에서는 해당 내용은 없습니다.

삭제하기는 아래 링크를 참조해서 작업해보세요.

게시판-댓글 페이지 이동없이 삭제하기

https://opentutorials.org/module/3774/28246


[미해결] 추가수정3. 페이지 이동없이 댓글 수정하기

참조 : XE/라이믹스 코멘트 페이지 이동 없이 수정하는 방법

https://opentutorials.org/module/3774/31679

(..계속 삽질중..)


[미해결] 윤삼님 팁을 적용한 스케치북 게시판에서 대댓글 창에서 파일을 업로드하면 글에 파일이 업로드되나, 해당 파일업로드창에서는 업로드한 파일이 사라져있음.
글과 파일이 서로 연결이 안되는 듯?