반응형

<INPUT TYPE="CHECKBOX" NAME="CHK" CLASS="CHECKDATA" VALUE="1">체크1
<INPUT TYPE="CHECKBOX" NAME="CHK" CLASS="CHECKDATA" VALUE="2">체크2
<INPUT TYPE="CHECKBOX" NAME="CHK" CLASS="CHECKDATA" VALUE="3">체크3

이렇게 체크박스가 동일한 클래스명으로 여러개 존재하고 라디오 버튼처럼 하나의 체크박스만 체크 가능하게 할 경우
체크박스의 체인지 이벤트에 아래와 같이 코딩해주면 끝남

           
$(".CHECKDATA").on('change', function() {
                $(".CHECKDATA").not(this).prop('checked', false);  
            });

반응형
Posted by Hippalus
,

반응형

망할 azure PaaS 환경의 클라우드 이관 작업을 진행하려다 보니 관련 부서에서 날짜 관련해서 제약사항이 생긴다란 이야기를 듣고 생각해보니 기존 소스들이 이관되면 엉망이 되겠다 싶어 미리 준비해보았다.

당장 javascript로 만들어진 new Date()만 보더라도 한국 시간과 미국 시간의 차이로 임계영역에 다다르면 날짜가 서로 꼬이게 될 것이란건 너무나 자명했다.

현재 서버호스팅 환경에선 new Date()시 2022-08-08 19:00:00이던게 
미국과 한국은 13시간의 차가 있으므로 azure PaaS 클라우드 환경에선 2022-08-09 20:00:00으로 보여지게 될테니 말이다. 

그리하여 기존의 new Date()대신 new AzureDate()를 호출하면 해당 함수내에서 알아서 시간계산을 해서 값을 돌려준다면 모든게 해결될 듯 보였다.
어차피 getFullYear(), getMonth(), getDate() 등의 함수는 new Date()로 받아온 시간객체를 통해 얻는 행위이므로 AzureDate()만 만들다면 이 모든건 소스 수정 없이 우아하게 처리 될 것이다.

아래가 그 결과물이다. 
    function AzureDate() {
        var dt;
        
        if (arguments.length == 0) {
            dt = new Date();
        } else if (arguments.length == 1) {
            dt = new Date(arguments[0]);
        }

        dt.setHours(dt.getHours() + 13);        
        
        return dt;
    }

특이한 부분은 arguments.length라는 부분이다.
new Date(), new Date("2022-08-08") 이렇게 인자를 넘겨서 객체를 생성하기 때문에 내가 만든 javascript 함수도 이에 대응할 필요가 있었다.

하지만 우리의 자바스크립트는 오버로딩을 지원하지 않는다.
https://www.geeksforgeeks.org/function-overloading-in-javascript/
Unlike the other programming languages, JavaScript Does not support Function Overloading
Here is a small code which shows that JavaScript does not support Function Overloading.

 

Function Overloading in JavaScript - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

따라서 arguments.length로 분기해준다면 훌륭하게 잘 처리가 가능하다.

다 만들어 놓고 azure cloud에 올려 테스트해봤더니 -_-
시간차가 벌어지지 않더라
생각해보니 javascript는 로컬이잖 -_-

내친김에 classic asp로도 만들어봤는데 마찬가지로 시간차가 없었단 -_-

    function AzureDate() 
        Dim dateVal
        dateVal = dateadd("h", 13, now())
        
        AzureDate = year(dateVal) & "-" & Right(String(2, "0") & month(dateVal), 2) & "-" & Right(String(2, "0") & day(dateVal), 2)
    end function

    function AzureNow() 
        Dim dateVal
        dateVal = dateadd("h", 13, now())
        AzureNow = dateVal
    end function


한국 서버에서 돌린 결과 2022-08-08 오후 7:30:00
8/8/2022 7:30:00 PM
azure Cloud서버가 한국에 있어서 그런건지...
이건 좀 이상하므로 설치한 담당자에게 물어보는 중

반응형
Posted by Hippalus
,

반응형

print.css
0.00MB

인터넷에 보면  javascript로 프린트를 하는데 동적인 TD의 높이 때문에 자칫 페이지가 넘어갈 때 화면이 짤리는 상황을 경험하게 된다.
이를 완벽하게 해결한 쉬운 소스를 공개한다.
보통 폼은 첫번째 장에는 헤더가 있고 다음장부터는 헤더가 없는 경우가 많다.
본 포스팅은 이러한 경우까지 대응하고 있다.
말은 거창하지만 사실 그냥 그만큼 자리 차지하고 있고 그 아랫부분부터는 동적으로 알아서 잘라주고 이어주고 알아서 잘 되니 신경 안써도 된다.

1. 페이지 상단에 본 포스팅의 print.css 첨부파일을 호출한다.

<link type="text/css" rel="stylesheet" href="/css/print.css" />


2. 스타일에 아래 코드를 추가한다.

<style>
@page { size: A4 }
* {
-webkit-print-color-adjust: exact !important; /*Chrome, Safari */
color-adjust: exact !important; /*Firefox*/
}
</style>

3. body에 print.css의 class인 A4사이즈를 지정한다.
<body class="A4">

4. 첫 페이지의 헤더를 위치시킨다. 내용은 각자 알아서 마음대로 교체하면 됨
id는 SECTIONPAGE1으로 하였다.
실질적인 출력 영역은 DIVTOPAREA class로 지정하였고 내용을 담당하는 DIV의 class는 DIVDATAAREA
끝으로 다음 tr의 높이가 페이지를 넘어서서 짤리게 될 경우 페이지 하단에 공백을 계산하여 넣어줘야 하므로 공백 DIV인 DIVBUFFERAREA가 추가되었다.
제목헤더인 DIVTOPAREA는 1페이지만 출력시키므로 SECTIONPAGE1에만 추가되어 있다.
참고로 여기서 거론한 class를 제외한 tdPrintWhite 클래스 등은 그냥 내 소스의 공통 css에서 사용되는 클래스이므로 무시하면 됨
<section class="sheet padding-10mm" id="SECTIONPAGE1">
<div class="DIVTOPAREA">
<table class="" width="100%" border="0" cellspacing="0" cellpadding="10">
<tr>
    <td class="tdPrintWhite" width="100%;" align="center"><h1>제목헤더영역</h1>
        <a href="#" class="btnblue" id="BTNPRINT">인쇄</a>
    </td>
</tr>
</table>
</div>
<br />
<div class="DIVDATAAREA"></div>
<div class="DIVBUFFERAREA"></div>
</section>

5.데이터를 출력시킬 SECTIONPAGE영역을 여유있게 미리 만들어 둔다.
동적으로 그때그때 생성해도 되지만 이게 편하다.
난 총 4페이지까지면 충분하므로 2부터 4까지 for문을 돌려 생성하였다.
<%
for iSEL = 2 to 4
%>

<section class="sheet padding-10mm" id="SECTIONPAGE<%=iSEL %>">
<div class="DIVDATAAREA"></div>
<div class="DIVBUFFERAREA"></div>
</section>

<%
next
%>

여기까지 진행했으면 일단 1차 준비는 끝났다.
이제 실질적으로 큰 영역에 모든 데이터들을 뿌려주고 페이지가 모두 로딩이 된 후 이 영역의 데이터들을 계산하여 앞서 만들어둔 SECTIONPAGE section의 DIVDATAAREA에 붙여넣기를 진행할 것이다.

6.보면 div에 id가 부여되었고 class도 편의상 id와 동일하게 부여하였다.
특이한 점은 rowspan이 2이다.
즉 아래와 같은 표형태이다.
굳이 왜 rowspan을 예로 들었냐면 그 이유는 잠시 후 아래에서 설명할 것이다.
이것 때문에 약간 고생을 한 경험이 있기 때문이다.

순번 성명 항목 현황
근거 일자 기종
<div id="DIVITEMBODY" class="DIVITEMBODY">
<table class="" width="100%" border="1" cellspacing="0" cellpadding="5">
<tr>
<td class="tdPrintGray" width="50px;" rowspan="2">순번</td>
<td class="tdPrintGray" width="*" rowspan="2">성명</td>
<td class="tdPrintGray" width="200px;" rowspan="2">항목</td>
<td class="tdPrintGray" width="400px;" colspan="3">현황</td>
</tr>
<tr>
<td class="tdPrintGray" width="200px;">근거</td>
<td class="tdPrintGray" width="100px;">일자</td>
<td class="tdPrintGray" width="100px;">기종</td>
</tr>
......for문을 통해 모든 데이터들을 각자 알아서 출력......
</table>
</div>

7.여기까지 HTML소스 끝이다.
이제 jQuery, javascript로 DIVITEMBODY의 데이터들을 계산해서 복사 붙여넣기를 하면 된다.
소스는 그냥 복사해서 붙여넣기 해보면 잘 동작할 것이다.
응용하려면 로직이 비교적 간단하니 바보 아니면 이해 가능한 수준이기도 하고 ;p
위에서 설명하기로 했던 내용으로 중요한 부분인 rowspan이 없는 헤더인 경우 "//헤더TR이 2줄 이므로 if (index == 0) 대신 if (index<= 1)로 사용"하라고 주석까지 달아 두었다.
SECTION을 4개가 아닌 10개를 만들었다면 for (nSectionPage = 2; nSectionPage <= 4; nSectionPage++)의 4를 10로 바꾸면 된다.
이 정도면 정말 이유식을 떠먹여줬다 본다.
나머진 복사 붙여넣기 하면 끝

<script>
    $(document).ready(function() {
        var bAppendEnd = false;
        var nLastTrIndex = 0;
        var nSectionPage = 1;

        var objSECTIONPAGE;
        var objTopArea;
        var objDataArea;
        var objBufferArea;

        objSECTIONPAGE = $("#SECTIONPAGE" + nSectionPage);

        objTopArea = objSECTIONPAGE.find($(".DIVTOPAREA"));
        objDataArea = objSECTIONPAGE.find(".DIVDATAAREA");
        objBufferArea = objSECTIONPAGE.find(".DIVBUFFERAREA");

        objDataArea.append($("#DIVITEMBODY").clone().attr("id", "DIVITEMBODY" + nSectionPage));

        var fSafeArea = 1118.740157 - (objTopArea.height() + 37.79527559);


        objSECTIONPAGE.find($(".DIVITEMBODY tr")).each(function(index, tr) {
            if (fSafeArea - $(this).height() > 0 && bAppendEnd == false) {
                fSafeArea = fSafeArea - $(this).height();
                nLastTrIndex = index;

                if (index == 0) {
                    if (fSafeArea - $(this).closest('tr').next('tr').height() < 0) {

                        bAppendEnd = true;

                        $(this).hide();
                        fSafeArea = fSafeArea + $(this).height();

                        console.log(objDataArea.html());
                        objDataArea.hide();
                    }
                }
            } else {
                bAppendEnd = true;
                $(this).hide();
            }
        });

        objBufferArea.height(fSafeArea);


        for (nSectionPage = 2; nSectionPage <= 4; nSectionPage++) {
            objSECTIONPAGE = $("#SECTIONPAGE" + nSectionPage);

            //objTopArea = objSECTIONPAGE.find($(".DIVTOPAREA"))
            objDataArea = objSECTIONPAGE.find(".DIVDATAAREA");
            objBufferArea = objSECTIONPAGE.find(".DIVBUFFERAREA");

            //objTopArea.append($("#DIVTOP").clone().attr("id", "DIVTOPAREA" + nSectionPage));
            objDataArea.append($("#DIVITEMBODY").clone().attr("id", "DIVITEMBODY" + nSectionPage));

            fSafeArea = 1118.740157 - 37.79527559;

            if (nLastTrIndex < objSECTIONPAGE.find($(".DIVITEMBODY tr")).length - 1) {
                bAppendEnd = false;

                objSECTIONPAGE.find($(".DIVITEMBODY tr")).each(function(index, tr) {
                    if (index <= 1) {   //헤더TR이 2줄 이므로 if (index == 0) 대신 if (index<= 1)로 사용
                        $(this).show();
                        fSafeArea = fSafeArea - $(this).height();
                    } else {
                        if (nLastTrIndex >= index) {
                            $(this).hide();
                        } else {
                            if (fSafeArea - $(this).height() > 0 && bAppendEnd == false) {
                                $(this).show();
                                fSafeArea = fSafeArea - $(this).height();

                                nLastTrIndex = index;

                            } else {
                                bAppendEnd = true;
                                $(this).hide();
                            }
                        }
                    }
                });

                objBufferArea.height(fSafeArea);
            } else {
                objSECTIONPAGE.hide();
            }

        }

        $("#DIVITEMBODY").hide();



        $("#BTNPRINT").click(function(e) {
            e.preventDefault();

            $("#BTNPRINT").hide();
            window.print();
            $("#BTNPRINT").show();
        });
    });  
</script>

끝으로 블로그 운영하는 사람들 중 복사하기 막아둔 인간들은 X잡고 반성해라
늬들도 어디서 줍줍한 알량한 잡지식인데 뭐 대단한 지식인냥 복사방지까지 해두고 난리부르스를 추는지 이해가 안간다.
만약 복사방지로 애써 찾은 소스 복사 할 수 없는 저질 블로그를 만나걸랑 크롬스토어에서 SuperCopy 슈퍼 카피를 추가하면 바로 복사되니 반드시 설치하여 복사에 성공하길 기원한다.
https://chrome.google.com/webstore/detail/supercopy-enable-copy/onepmapfbjohnegdmfhndpefjkppbjkm

 

SuperCopy 슈퍼 카피

오른쪽 키 허용, 선택 허용, 복사 허용, 붙 여 넣 기 허용.

chrome.google.com

이상 전달 끝

반응형
Posted by Hippalus
,