Rhymix(XpressEngine) Tips

본 토픽은 현재 준비중입니다. 홈페이지제작-CMS-XpressEngine에 참여하시면 완성 되었을 때 알려드립니다.

게시판-글, 댓글 추천, 비추천 경고창 없이 동작하게 하기

XE는 원래 추천만 가능하고, 추천 후에 경고창 형태로 추천했습니다라고 메세지가 뜨는게 기본입니다.

아이고-_-;

이걸 라이믹스로 넘어오면서부터 추천, 비추천이 가능해졌고,

마찬가지 기본 스킨은 추천이나 비추천 후에 경고창이 뜨는게 기본인 건데,

 

요즘에야 포털댓글이나 SNS댓글 쪽이 워낙 UX적으로 사용자에게 편의를 주다보니,

일부 유료 스킨 제외하고는 과거의 유물이 업그레이드 되지 못하고 계속 그걸 그대로 써왔었는데..

요청하시는 분들이 너무 많아서 이 부분도 개선했습니다.

 

https://eond.com/xe/441138

이 코드도 작년에 다른 분께서 작업하신 스킨 부분 참조해서 일부만 조금 손봤습니다.

 

1. 글 추천

1) 스킨 코드

<div class="app-article-vote" data-target-srl="{$oDocument->document_srl}">
    {@
    $isMyVoted = $oDocument->getMyVote() == 1;
    $voteActiveClassName = $isMyVoted ? 'active' : null;
    }
    <a class="app-article-toolbar__item app--is-vote app-tooltip {$voteActiveClassName} <!--@if($isMyVoted)-->true<!--@end-->" title="좋아요" data-type="up" onclick="alArticleVote(this)">

        <div class="app-icon">
            <!--@if($isMyVoted)-->
            <!--<ion-icon name="triangle-sharp"></ion-icon>-->
            <i class="thumbup"></i>
            <!--@else-->
            <!--<ion-icon name="triangle-sharp"></ion-icon>-->
            <i class="thumbup"></i>
            <!--@end-->
        </div>
        <span class="app-article-vote__count">
         {$oDocument->get('voted_count') > 0 ? $oDocument->get('voted_count') : '0'}
        </span>
    </a>

    {@
    $isMyBlamed = $oDocument->getMyVote() == -1;
    $blameActiveClassName = $isMyBlamed ? 'active' : null;
    }
    <a class="app-article-toolbar__item app--is-blame app-tooltip {$blameActiveClassName} <!--@if($isMyBlamed)-->true<!--@end-->" title="싫어요" data-type="down" onclick="alArticleVote(this)">

        <div class="app-icon">
            <!--@if($isMyBlamed)-->
            <i class="thumbdown"></i>
            <!--<ion-icon name="triangle-sharp" class="rotate"></ion-icon>-->
            <!--@else-->
            <i class="thumbdown"></i>
            <!--<ion-icon name="triangle-sharp" class="rotate"></ion-icon>-->
            <!--@end-->
        </div>
        <span class="app-article-vote__count">
          {$oDocument->get('blamed_count') < 0 ? $oDocument->get('blamed_count') : '0'}
        </span>

    </a>
</div>

 

2)자바스크립트코드

function appToast(message, type) {
    const element = document.createElement('div')
    element.className = 'app-toast'

    if(type) {
        element.className = element.className + ' ' + type
    }
    const text = document.createTextNode(message)
    element.appendChild(text)

    $(document.body).append($(element).fadeIn())

    setTimeout(function() {
        $(element).fadeOut('normal', function() {
            $(this).remove()
        })
    }, 1000)
}

function alDocumentAjaxCall(targetSrl, action, callback) {
    const params = {
        target_srl: targetSrl,
        cur_mid: window.current_mid,
        mid: window.current_mid,
        module: 'document',
        act: action,
        _rx_ajax_compat: 'JSON',
        _rx_csrf_token: getCSRFToken()
    }

    $.ajax({
        type: "POST",
        dataType: "json",
        url: request_uri,
        data: params,
        processData: (action !== 'raw'),
        success: callback,
        error: function(err) {
            console.log(err)
        }
    })
}

function alArticleVote(el) {
    console.log(el)
    const targetSrl = $(el).parent().attr('data-target-srl')
    const type = $(el).attr('data-type')
    const isActive = $(el).hasClass('active')


    if(type === 'down') {
        var transformedType = 'Down'
    } else {
        var transformedType = 'Up'
    }

    console.log(targetSrl, type, isActive)

    // 이미 액티브 상태인 경우 취소
    if(isActive) {
        var action = 'procDocumentVote' + transformedType + 'Cancel'
    } else {
        var action = 'procDocumentVote' + transformedType
    }

    // 콜백
    function callback(res) {
        if(res.error) {
            // console.log(el)
            // appToast(res.message, 'danger')
            return
        }

        var appliedCount = res.voted_count || res.blamed_count

        var getVoteCount = Number($(el).find('.app-article-vote__count').text())

        if(appliedCount) {
            var count = appliedCount

        } else if(getVoteCount > -1) {
            var count = getVoteCount -1

        } else {
            var count = getVoteCount + 1
        }

        $(el).find('.app-article-vote__count').text(count)
        $(el).toggleClass('active')

        // appToast(res.message)
    }

    alDocumentAjaxCall(targetSrl, action, callback)
}

 

3) CSS코드

$color-success:red;
$color-danger:blue;

.app-article-vote {
  display: flex;
  align-items: center;
  margin-bottom: 1.6rem;
  justify-content: center;

  //border: 1px solid red;
  a{
    display:flex;
    flex-direction: column-reverse;
    justify-content: flex-end;
    position: relative;
    text-decoration: none;

    width: 70px;
    height: 70px;
    border: -1px solid red;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    margin: 1rem;
    box-shadow: 0 3px 6px 0px rgba(0,0,0,.2);
    &:hover{
      text-decoration: none;
    }
    &.true{
      background:#ECF0F6;
      box-shadow:none;
    }
    &.inactive{
      background:#fff !important;
      box-shadow: 0 3px 6px 0px rgba(0,0,0,.2) !important;
    }
    &.active{
      background:#ECF0F6 !important;
      box-shadow:none !important;
    }
  }
  .app-article-vote__count{
    font-size: 23px;
    font-weight: 800;
    position: relative;
    text-align: center;
    //height: 31px;
    z-index: 1;
  }
  .ion-icon{
    font-size: 32px;
    &.rotate{
      //display: inline-block;
      transform: rotate(180deg);
    }
  }
  .app--is-vote {
    cursor: pointer;
    color: $color-success !important;
    &.active {
      //color: $color-success !important;
      .app-article-vote__count{
        //color: $color-success !important;
      }
    }
  }
  .app--is-blame {
    cursor: pointer;
    color: $color-danger !important;
    &.active {
      //color: $color-danger !important;
      .app-article-vote__count{
        //color: $color-danger !important;
      }
    }
  }
}

 

이렇게 하면 글 추천이 끝났고, 댓글은 또 코드가 다릅니다..

 

2. 댓글

1) 스킨코드

<div class="voteup">
    <a cond="$comment->getVote() === false || $comment->getVote() < 0" href="javascript:;" onclick="doCallModuleAction('comment','procCommentVoteUp','{$comment->comment_srl}',this);return false;"|cond="$is_logged" class="voted"><i class="thumbup"></i><span class="num">{$comment->get('voted_count')}</span></a>
    <a cond="$comment->getVote() > 0" href="#" onclick="doCallModuleAction('comment','procCommentVoteUpCancel','{$comment->comment_srl}',this);return false;"|cond="$is_logged" class="voted me"><i class="thumbup"></i><span class="num">{$comment->get('voted_count')}</span></a>
</div>
<div class="votedown">
    <a cond="$comment->getVote() === false || $comment->getVote() > 0" href="javascript:;" onclick="doCallModuleAction('comment','procCommentVoteDown','{$comment->comment_srl}',this);return false;"|cond="$is_logged" class="voted"><i class="thumbdown"></i><span class="num">{$comment->get('blamed_count')}</span></a>
    <a cond="$comment->getVote() < 0" href="#" onclick="doCallModuleAction('comment','procCommentVoteDownCancel','{$comment->comment_srl}',this);return false;"|cond="$is_logged" class="voted me"><i class="thumbdown"></i><span class="num">{$comment->get('blamed_count')}</span></a>
</div>

div로 감싼 부분이 각각 추천, 비추천이고, 그 안에서 윗쪽에 있는 a태그가 추천하기 전, 아랫쪽에 a 태그가 내가 추천한 코드입니다.

 

2) 자바스크립트코드

<script>
    function doCallModuleAction(module, action, target_srl, source) {
        var button = jQuery(source);
        var count = button.find(".num").html();
        // var params = {
        //     target_srl : target_srl,
        //     cur_mid    : current_mid,
        //     mid        : current_mid
        // };
        var params = new Array();
        params['target_srl'] = target_srl;
        params['cur_mid'] = '{$mid}';
        params['mid'] = '{$mid}';

        exec_xml(module, action, params, function(){
            if(action=='procCommentVoteDown'){
                // 비추
                button.attr("onClick","doCallModuleAction('comment','procCommentVoteDownCancel','"+target_srl+"',this);return false;").addClass("me");
                button.find(".num").html(Number(count)-1);
            }else if(action=='procCommentVoteDownCancel'){
                // 비추 취소
                button.attr("onClick","doCallModuleAction('comment','procCommentVoteDown','"+target_srl+"',this);return false;").removeClass("me");
                button.find(".num").html(Number(count)+1);
            }else if(action=='procCommentVoteUpCancel'){
                // 추천취소
                button.attr("onClick","doCallModuleAction('comment','procCommentVoteUp','"+target_srl+"',this);return false;").removeClass("me");
                button.find(".num").html(Number(count)-1);
            }else{
                // 추천
                button.attr("onClick","doCallModuleAction('comment','procCommentVoteUpCancel','"+target_srl+"',this);return false;").addClass("me");
                button.find(".num").html(Number(count)+1);
            }
        });
    }


    function doCommentVoteCancel(target_srl,type,count,count2,source){
        var button = jQuery(source);
        if(type == 'vote'){
            var proc = 'procCommentVoteUpCancel';
        }else{
            var proc = 'procCommentVoteDownCancel';
        }
        var params = new Array();
        params['target_srl'] = target_srl;
        params['mid'] = '{$mi->mid}';
        jQuery("#ink_loading").show();
        exec_xml('comment', proc, params, function(){
            jQuery("#ink_loading").fadeOut(200);
            jQuery("#ink_done").fadeIn(200);
            setTimeout(function(){
                jQuery('#ink_done').fadeOut(500);
            },400);
            button.removeClass("submitted");
            if(type == 'vote'){
                button.attr("onClick","doCommentVote('"+target_srl+"','vote',"+(count-1)+","+count2+",this);return false;");
                <!--@if($mi->use_cmt_vote != 'vote')-->
                button.next().attr("onClick","doCommentVote('"+target_srl+"','blame',"+count2+","+(count-1)+",this);return false;");
                <!--@end-->
                button.find(".voted_count").html(count-1);
            }else{
                button.attr("onClick","doCommentVote('"+target_srl+"','blame',"+(count-1)+","+count2+",this);return false;");
                button.prev().attr("onClick","doCommentVote('"+target_srl+"','vote',"+count2+","+(count-1)+",this);return false;");
                button.find(".voted_count").html(-count+1);
            }
        });
        setTimeout(function(){
            jQuery("#ink_loading").fadeOut(200);
        },1000);
    }
</script>

아랫쪽 코드는 참조한 코드입니다.

 

3) CSS코드

.voteup,.votedown{
  a.me{
    .thumbup{
      background-image: url("../img/ico-thumbs-up-fill.svg");
    }
    .thumbdown{
      background-image: url("../img/ico-thumbs-down-fill.svg");
    }
  }
}

CSS 쪽은 내가 추천한 경우에 해당 이미지를 바꿔줬습니다.

 

이렇게 하면... 기본 구현 동작은 다 됩니다.

댓글

댓글 본문
graphittie 자세히 보기