지난번에 게시판 모듈 스킨(특히, 스케치북)을 이용해 서명 그리기를 끼워넣는 팁을 소개해드린 바 있습니다. (아래 링크 참조)

https://xetown.com/lakepark/520085

 

해당 게시물에서 보시는 바와 같이 @웹지기님을 통해 서명 패드가 (1) 복수로 존재하거나 (2) 필수가 아닐 수도 있는 경우 등에 대해 피드백을 받기도 했습니다.

그래서 이 두 가지 경우를 우선적으로 고려해서 반복문과 기타 구문들을 활용해서 코드를 다시 짜봤습니다.

(오늘 낮술부터 시작해서 정신이 몽롱한 관계로 지난번처럼 자세한 설명을 못드리는 점 양해 부탁드리겠습니다)

 

1. 준비물 구하기

- 앞선 게시물에도 쓰긴 했지만, 다시 한번 말씀 드리겠습니다.

- 일단 http://www.jqueryscript.net/other/Smooth-Signature-Pad-Plugin-with-jQuery-Html5-Canvas.html로 갑니다.

- Download 받으세요.

- jquery.signaturepad.css 파일은 css 폴더에 저장해줍니다. (스케치북 스킨의 css 폴더를 말하는 거예요)

- numeric-1.2.6.min.js, bezier.js, jquery.signaturepad.js, js/json2.min.js 등의 파일은 js 폴더에 저장해줍니다. (마찬가지로 스케치북 스킨의 js 폴더)

- 그러면, 확장변수를 만들어보겠습니다.

 

2. 확장변수 만들기

- 게시판 관리 > 사용자 정의 > 추가로 들어가서 확장변수를 만듭니다.

- 여기서 '사용자 정의 이름'을 signature1로 합니다. (♦반드시 그렇게 하셔야만 소스가 제대로 돌아갑니다)

- '입력항목 이름'은 원하시는 대로 하세요. 저는 그냥 '서명'이라고 했습니다.

- '입력형식'은 무엇으로 하든 관계가 없으니 가급적이면 그냥 내버려둡니다 ㅋ

- 서명은 필수일 테니 '필수항목'에선 '예'를 체크합니다.

- '설명'은 대강 이렇게 해보죠. '윗칸에 서명을 그려 넣어주세요.'

- '검색'은 '아니오'를 권장합니다.

- 그리고 서명패드를 두 개 이상으로 추가하고 싶으시다면, 순차적으로 signature2, signature3, signature4, ... 등으로 순번을 지켜주시면 됩니다.

 

3. write_form.html 수정

- 스킨 폴더에서 write_form.html 파일을 꺼낸 뒤 수정을 시작합니다.
 

- 첫 번째. 파일 상단 부분에 보면 <form action="/" method="post" onsubmit="return procFilter(this, window.insert)" class="bd_wrt bd_wrt_main clear">라는 곳이 있을 겁니다. 얘를 다음과 같이 바꿔주세요.

{@
    if(count($extra_keys)):
        foreach($extra_keys as $val):
            $eids[] = $val->eid;
        endforeach;
    endif;
}
<form action="/" method="post" onsubmit="<!--@if(strpos($eids,'signature')!==false)-->dataURL();<!--@end-->return procFilter(this, window.insert)" class="bd_wrt bd_wrt_main clear">

- 이렇게 해야 확장변수 목록 중에 'signature'가 들어가 있는 경우에만 서명 입력 부분이 문자열로 변환돼서 서버에 전달이 됩니다. 그림이 안 그려지면요? 해당 변수가 필수인 경우에는 "서명 값은 필수입니다." 같은 경고창이 뜨면서 문서 등록이 중지되겠고, 선택인 경우에는 아무런 값도 전달하지 않은 채로 문서가 등록될 겁니다.
 

- 두 번째, 잘 찾아보시면 <table cond="count($extra_keys)" class="et_vars exForm bd_tb">이라는 부분이 있을 겁니다. 이게 바로 확장변수 입력하는 테이블이에요.

- 그 아래아래에 <tr loop="$extra_keys=>$key,$val"> 같은 태그가 있을 겁니다. 얘를 아래와 같이 수정해봅니다. 이렇게 하면 확장변수값을 입력하는 테이블은 서명 패드(들)만 빼고 입력 폼을 띄우게 됩니다.

<tr loop="$extra_keys=>$key,$val" cond="substr($val->eid,0,9)!='signature'">


- 세 번째, 마지막으로 하나 더. 확장변수 입력 table 태그 뒤에 본격적으로 서명 부분 코딩을 시작합니다. 대략 아래와 같이 해보겠습니다.(이번에는 지난번과 달리 한번에 쭉 갑니다ㅎㅎ)

<!--// 서명 받기 -->
<block cond="strpos($eids,'signature')!==false">
    <load target="css/jquery.signaturepad.css" />
    <load target="js/numeric-1.2.6.min.js" />
    <load target="js/bezier.js" />
    <load target="js/jquery.signaturepad.js" />
    <load target="js/json2.min.js" />
    {@ $i=1; }
    <div class="sigPad" style="width:296px; display:table; margin:0 auto;" loop="$extra_keys=>$key,$val" cond="substr($val->eid,0,9)=='signature'">
        <ul class="sigNav">
            <h3>{$val->name}<em cond="$val->is_required=='Y'">*</em></h3>
            <li class="clearButton"><a href="#clear">{$lang->reload}</a></li>
        </ul>
        <div class="sig sigWrapper" style="height:100px;">
            <div class="typed"></div>
            <canvas class="pad" id="cy-sig{$i}" width="294" height="100"></canvas>
            <input type="hidden" name="extra_vars{$key}" id="cy-sig_data{$i}" class="output<!--@if($val->is_required=='Y')--> cy-req<!--@end-->" value="{$oDocument->getExtraEidValue($val->eid)}">
        </div>
        <p style="margin-top:5px;text-align:center;font-size:11px;">{$val->desc}</p>
        {@ $i++ ;}
    </div>
<script>
// 서명 옵션 설정
jQuery(document).ready(function(){
    jQuery('.sigPad').signaturePad({
        drawOnly:true,
        drawBezierCurves:true,
        lineTop:90
    });
});
// 서명 패드 갯수(=n-1) 자동 설정
var n = '{$i}';
// 서명 관련 변수 정의
for(var i=1;i<n;i++) {
    eval('canvas'+i+'=document.getElementById("cy-sig'+i+'")'),
    eval('context'+i+'=canvas'+i+'.getContext("2d")'),
    eval('cv_data'+i+'=document.getElementById("cy-sig_data'+i+'")'),
    eval('req'+i+'=cv_data'+i+'.className.split(" ")[1]'),
    eval('val'+i+'=cv_data'+i+'.value');
}
// 서명 이미지값 문자열 전달 처리
function dataURL(){
    for(var i=1;i<n;i++) {
        if(eval('cv_data'+i).value != ''){
            eval('cv_data'+i).value = eval('canvas'+i).toDataURL();
        } else {
            if(eval('req'+i) == 'cy-req') {
                return false;
            } else eval('cv_data'+i).value = '';
        }
    }
}
// 수정시 서명 문자열의 이미지 로드
if(window.addEventListener) {
    for(var i=1;i<n;i++) {
        if(eval('val'+i) != '') window.addEventListener('load', cnvs2Img, false);
    }
function cnvs2Img(){
    for(var i=1;i<n;i++) {
        eval('image'+i+' = new Image()');
        eval('image'+i).src = eval('val'+i);
        eval('image'+i).onload = function(){
            for(var i=1;i<n;i++) {
                eval('context'+i).drawImage(eval('image'+i),0,0);
                if(eval('val'+i) != '') {
                    eval('cv_data'+i).value = eval('canvas'+i).toDataURL();
                } else {
                    eval('cv_data'+i).value = '';
                }
            }
        }
    }
}
}
</script>
</block>

 

4. _read.html 수정

- 주지하시듯, 게시물 본문은 _read.html. 따라서 확장변수로서 signature1~n도 여기서 일람해볼 수 있습니다. 다만, 서버로 전달된 복잡한 문자열을 다른 확장변수처럼 바로 출력할 순 없겠죠.

- 여기서 <caption class="blind">Extra Form</caption>라는 구문이 들어간 두 개의 table을 볼 수 있을 겁니다. '스킨 설정 > 본문 일반 설정 > 확장변수 위치'가 '본문 안에(기본)'인 경우엔 아래쪽 table, '제목 아래'인 경우엔 윗쪽 table이 될 겁니다.

- 이 테이블'들'에 td 태그 부분이 있습니다. 대개는 이렇게 되어 있죠. 평점 매기는 게시판을 구분 하기 위한 코드들인 거 같네요.

<td cond="$val->eid!='rating'">{$val->getValueHTML()}</td>
< td cond="$val->eid=='rating'" class="rating"><span class="starRating" title="{$val->getValueHTML()}{$lang->score}"><span style="width:{$val->getValueHTML()*10}%">{$val->getValueHTML()}</span></span></td>

- 위의 코드'들'을 다음과 같이 바꿔줍니다. 네, 바로 두 번째 줄이 핵심입니다. 서명 변수(들)에 한해서 이미지로 불러오는 거죠. 입력되어 있는 값은 이미지의 dataURL이니까요ㅎㅎ

<td cond="$val->eid!='rating'&&substr($val->eid,0,9)!='signature'">{$val->getValueHTML()}</td>
<td cond="$val->eid!='rating'&&substr($val->eid,0,9)=='signature'"><img src="{$val->getValueHTML()}" /></td>
<td cond="$val->eid=='rating'&&substr($val->eid,0,9)!='signature'" class="rating"><span class="starRating" title="{$val->getValueHTML()}{$lang->score}"><span style="width:{$val->getValueHTML()*10}%">{$val->getValueHTML()}</span></span></td>

 

이상입니다.

윤삼

profile
아무래도 중급 초반 수준의 코딩 오타쿠인 것 같습니다.
  • profile

    .

  • profile profile
    ㅎㅎ 이게 최종 버전일 듯합니다~
  • profile
    cms까지 하는 경우에 저는 php워드를 이용해서 해당 건을 워드파일로 생성하게 해주고 있습니다.
    cms후원받는 분들은 요새 꼭 필요한걸겁니다.
  • profile profile
    네, 저도 cms회원 받다가 알게 된 팁이에요. 비영리단체 사이트들에 도움이 될 것 같습니다.
  • profile profile
    이런 싸인이 들어간 서류를 첨부해서 cms로 해당회원의 계좌에서 출금 되도록 cms 서비스회사에 신청하는 건가요?!

    cms 이용이 조건이 까다롭지는 않나 보네요.
  • profile profile
    소규모 비영리단체여서 가능할지도 모르겠어요.
    암튼 저렇게 받은 걸 pdf로 출력해서 담당자에게 전달하면 알아서 잘 처리하더라구요ㅎㅎ
  • profile
    좋은 팁 감사합니다. 이번 버전으로 변경 완료했습니다. 감사합니다.
  • profile profile
    덕분에 팁을 업그레이드할 수 있었습니다. 감사합니다~
  • profile
    추천! 유용한 팁입니다.
  • profile profile
    ㅎㅎ 감사합니다~
    ExtendKR님이 만들고 착한인연님이 수정하신 애드온도 있으니 그쪽이 더 간편할 겁니다!
    https://xetown.com/lakepark/527360
  • ?
    댓글 쓸때도 서명할 수 있도록 할 수 있을까요?? 도움 좀 부탁드려요^^
  • ? profile
    확장변수를 이용해야 해서 커스터마이징을 많이 하든가 해야 할 거예요. 댓글에까지 적용하려면 그냥 제작 의뢰가 낫지 않을까 싶습니다.
  • ?

    댓글 서명은 힘들거 같아 본문 내에 서명을 만들려고 하는데요.

    문서를 클릭해서 보고 바로 확인자 서명을 하려고 하는데요. 

    본문에서 바로 확인자 서명을 하면 문서 보기(read)에 서명 바로 밑에 또 확인자 서명이 생기게 하려구요.

    기초지식이 없어서 잘 안되네요. 텍스트는 되는데 서명 이미지는 안되네요.
    아래 스크립트 내용 적으니 수정 좀 부탁드려도 될까요??

    _read.html 파일입니다. (확장변수는 sign으로 했습니다. 서명자와 확인자 구분을 위해) 


    <!--//본문내 서명 추가-->
    <block cond="$logged_info->member_srl==$oDocument->get('member_srl')||$grant->manager">
    <block cond="$click">
    {@
    $oDB = &DB::getInstance();
    $sql = $oDB->_query('SELECT COUNT(*) as count FROM xe_document_extra_vars WHERE document_srl='.$document_srl.' and module_srl ='.$module_info->module_srl.' and eid="sign"');
    $rec_count = $oDB->_fetch($sql);
    }
    <!--@if($rec_count->count==0)-->
    {@
    $query = $oDB->_query('INSERT INTO xe_document_extra_vars (module_srl, document_srl,var_idx,lang_code,value,eid) VALUES ('.$module_info->module_srl.','.$document_srl.',4,"ko","'.$click.'","sign")');
    }
    <!--@else-->
    {@
    $query = $oDB->_query('update xe_document_extra_vars set value = "'.$click.'" where document_srl = '.$document_srl.' and module_srl = '.$module_info->module_srl.' and eid = "sign"');
    }

    <!--@end-->
    <script>location.href="{str_replace('amp;', '', getUrl('click', ''))}"</script>
    </block>
    <!--// 서명 받기 -->
    <cond="strpos($eids,'signature')!==false">
    <load target="css/jquery.signaturepad.css" />
    <load target="js/numeric-1.2.6.min.js" />
    <load target="js/bezier.js" />
    <load target="js/jquery.signaturepad.js" />
    <load target="js/json2.min.js" />
    {@ $i=1; }
    <div class="sigPad" style="width:296px; display:table; margin:0 auto;" loop="$extra_keys=>$key,$val" cond="substr($val->eid,0,9)=='sign'">
    <ul class="sigNav">
    <h3>{$val->name}<em cond="$val->is_required=='Y'">*</em></h3>
    <li class="clearButton"><a href="#clear">{$lang->reload}</a></li>
    </ul>
    <div class="sig sigWrapper" style="height:100px;">
    <div class="typed"></div>
    <canvas class="pad" id="cy-sig{$i}" width="294" height="100"></canvas>
    <input type="hidden" name="extra_vars{$key}" id="cy-sig_data{$i}" class="output<!--@if($val->is_required=='Y')--> cy-req<!--@end-->" value="{$oDocument->getExtraEidValue($val->eid)}">
    </div>
    <p style="margin-top:5px;text-align:center;font-size:11px;">{$val->desc}</p>
    {@ $i++ ;}
    </div>
    <script>
    // 서명 옵션 설정
    jQuery(document).ready(function(){
    jQuery('.sigPad').signaturePad({
    drawOnly:true,
    drawBezierCurves:true,
    lineTop:90
    });
    });
    // 서명 패드 갯수(=n-1) 자동 설정
    var n = '{$i}';
    // 서명 관련 변수 정의
    for(var i=1;i<n;i++) {
    eval('canvas'+i+'=document.getElementById("cy-sig'+i+'")'),
    eval('context'+i+'=canvas'+i+'.getContext("2d")'),
    eval('cv_data'+i+'=document.getElementById("cy-sig_data'+i+'")'),
    eval('req'+i+'=cv_data'+i+'.className.split(" ")[1]'),
    eval('val'+i+'=cv_data'+i+'.value');
    }
    // 서명 이미지값 문자열 전달 처리
    function dataURL(){
    for(var i=1;i<n;i++) {
    if(eval('cv_data'+i).value != ''){
    eval('cv_data'+i).value = eval('canvas'+i).toDataURL();
    } else {
    if(eval('req'+i) == 'cy-req') {
    return false;
    } else eval('cv_data'+i).value = '';
    }
    }
    }
    // 수정시 서명 문자열의 이미지 로드
    if(window.addEventListener) {
    for(var i=1;i<n;i++) {
    if(eval('val'+i) != '') window.addEventListener('load', cnvs2Img, false);
    }
    function cnvs2Img(){
    for(var i=1;i<n;i++) {
    eval('image'+i+' = new Image()');
    eval('image'+i).src = eval('val'+i);
    eval('image'+i).onload = function(){
    for(var i=1;i<n;i++) {
    eval('context'+i).drawImage(eval('image'+i),0,0);
    if(eval('val'+i) != '') {
    eval('cv_data'+i).value = eval('canvas'+i).toDataURL();
    } else {
    eval('cv_data'+i).value = '';
    }
    }
    }
    }
    }
    }
    </script>
    <div><p align="right">
    <input type='image' src="/img/footprint.png" onClick="location.href='{getUrl('click',$val->getValueHTML())}'" />

    </div></p>
    </block>

  • ? profile
    확장변수 입력 여부를 확인해서, 미입력시 확장변수 입력 폼필드를 출력하고, 입력시에는 확장변수 입력값을 출력하거나 아무 것도 출력하지 않는 거 맞죠?

    그나저나 코드만 봐서는 저도 잘 몰라요ㅜ
    소스코드를 코드하이라이터(?) 등으로 보기 좋게 재구성한 뒤, 질문게시판에 별도 게시물로 남기시거나 제작의뢰를 하시는 게 좋을 것 같습니다.