반응형

망할 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
,

반응형

앱스토어를 통해 Xcode를 업데이트 하다보면 종종 업데이트 멈춤 현상을 경험하게 된다.
수년째 반복되는 일임에도 애플은 나몰라라
이것 때문에 애플개발자 지원센터에 유선 문의도 했었지만 그 이후에도 또 이렇게 먹통이 돼버렸다.
아래 대기상태로 몇시간을 지켜봐도 동일하다.

무한 로딩 증상이 지속될 경우 아래 내용대로 시도하고 리부팅도 하다보면 언젠간 업데이트 버튼을 마주할 수 있게 된다.
업데이트 버튼을 누르면 다시 처음부터 8기가가 넘는 Xcode 업데이트 파일을 다운받게 되고 운이 좋다면 업데이트를 성공시킬 수 있다.
그나마 파랑 로딩 인디케이터라면 업데이트에 희망적이라 본다.
회색 로딩 인디케이터라면 절망적이지 싶다.
일단 아래 내용대로 터미널을 통해 캐시 파일들을 삭제하고 운좋게 다시 업데이트를 재시작 하였지만 작성중인 현 상태에서도 동일하게 설치 중 대기 상태이긴 하다.
회색 인디케이터가 아니라 좀 기다리면 되지 싶긴한데..성공하면 댓글로 성공 여부를 남겨두겠다.



앱스토어 캐시 삭제
1. 앱스토어 임시 파일 삭제
터미널(terminal) 실행
터미널 상태에서 아래 명령어 실행 후 Finder가 뜨면 해당 폴더 모조리 삭제
open $TMPDIR../C/com.apple.appstore/

2. 앱스토어 캐시 파일 삭제
터미널 상태에서 아래 명령어 실행 후 Finder가 뜨면 해당 폴더 모조리 삭제
open ~/Library/Caches/com.apple.appstore

3. 기타 앱스토어에이전트 중지
터미널(terminal) 실행
터미널 상태에서 pkill -9 -f appstoreagent 명령어 입력

오죽했으면 이용자가 앱스토어 Xcode 리뷰에 분노의 리뷰를 달아놨을까?

반응형
Posted by Hippalus
,

반응형

튜닝도 거치고 쿼리분석기에서 예상실행계획상 누락된 인덱스도 없으며 0.1초만에 잘 나오는 쿼리상으론 아무 문제 없는 쿼리임에도 불구하고 웹페이지에서 실행하면 15초씩 걸리는 이상한 현상이 발견되었다.


가만히 놔둬선 안되겠다 싶어 구글링을 해보니 나와 같은 증상을 겪은 사람들이 이미 여럿 존재함을 확인할 수 있었다.

이유는 ARITHABOART 이녀석 때문인데 시퀄서버에선 기본값이 ON이지만 ADO에선 아래 표처럼 기본값이 OFF


결론은 쿼리 날릴 때 ADODB의 설정을 건드려주면 된다.
Static Query인 경우엔 쿼리문 앞에 SET ARITHABORT ON을 넣어주고
Set objCmd = Server.CreateObject("ADODB.Command")
    SQL = ""
    SQL = SQL & vbCrLf & "SET ARITHABORT ON"
    SQL = SQL & vbCrLf & "SELECT"
    ......
    With objCmd
    .ActiveConnection = dbConn
    .CommandType = adCmdText
    .CommandText = SQL
    
               .Parameters.Append .CreateParameter("param", adDate, adParamInput, , paramdata)
    End With
    
    Set rs = Server.CreateObject("ADODB.RecordSet")
    rs.CursorLocation = adUseClient
    rs.Open objCmd, , adOpenStatic, adLockReadOnly

    If rs.EOF Then
    Else
    End If

    rs.Close
    Set rs = Nothing
Set objCmd = Nothing

Stored Procedure인 경우
SqlConnection dbConn = new SqlConnection(strConnection);

dbConn.Open();
SqlCommand cmdAritabort = new SqlCommand("SET ARITHABORT ON", dbConn);
cmdAritabort.ExecuteNonQuery();
           
SqlCommand cmd = new SqlCommand("dbo.usp_example", dbConn);
cmd.CommandType = CommandType.StoredProcedure;

SqlDataAdapter adapter = new SqlDataAdapter(com);
adapter.Fill(table);

dbConn.Close();


관련하여 더 자세히 느끼고 싶다면 Slow in the Application, Fast in SSMS? Understanding Performance Mysteries란 버거형님의 진중하고 장대한 글을 참고해보길 바란다.
https://www.sommarskog.se/query-plan-mysteries.html
해당 글에선 좀 다르게 이야기 해주던데 너~~~무 길고 난 ARITHABOART ON 설정으로 느린 쿼리를 해결하였으므로 이쯤에서 만족하려 한다.

반응형
Posted by Hippalus
,

반응형

일전에 네이버 서치어드바이저(searchadvisor.naver.com)를 통해 사이트 등록을 요청하였으나 수집보류라는 어처구니 없는 상태가 지속되었다.

검색해보니 몇가지 방법이 존재하는데 그 중 그나마 해결 가능한 방법이 고객센터를 통해 요청을 하는 방법이 있어 고객센터를 통해 문의를 접수하였으나 아니나 다를까 아래와 같은 같잖은 답변을 받아볼 수 있었다.

안녕하세요. **** 고객님,문의하신 내용에 답변드립니다. 

네이버는 모든 사이트 및 웹문서의 수집/반영을 보장하지 않습니다.
수집보류가 노출되는 것은 최적화 여부, 사이트 신뢰도, 사이트 상태 등에 따라 다양한 원인이 있으며, 수집 요청한 사이트의 수집 여부를 판단하기 어려워 보류가 된 경우를 뜻합니다.

웹마스터도구의 수집 요청 기능은 수집 시스템에게 수집 대상 URL을 전달하는 도우미의 역할만을 담당하며 수집성공이 되더라도 검색결과 노출을 보장할 수 없습니다.

장황하게 되도 않는 이야기를 늘어놓았으나 요지는 니 말은 알겠는데 그냥 가만히 있어라라는 이야기다.
ㅎㅎㅎㅎㅎㅎㅎ
말은 못하겠지만 이유는 알만하다.

구글은 사이트 등록이 완료되어 크롤링이 되고 있건만 네이버는 이런 답변만을 줄 뿐이다.

혹자는 존버하면 언젠간 될 수 도 있다 하지만 바다 건너 미국 기업은 따박 따박 크롤링 해가주는데 국내 기업인 네이버는 이런 식의 반응에 미온적인 태도이니 화가 나지 않을 수 없다.
등록을 요청한 사이트엔 아무런 문제가 없다.
PC, mobile 모두 부트스트랩을 통해 사이트 체크시 정상 확인이 가능하고 사이트맵 xml 제출, meta tag 등 시키는 대로 모든것을 완벽히 수행했음에도 이런식의 변명으로 일관될 뿐이다.

그럼에도 불구하고 크롤링이 불가하니 답답 그 자체가 아닐 수 없다.

 

반응형
Posted by Hippalus
,

반응형

iframe으로 불러들인 컨텐츠의 높이만큼 부모창에서 iframe의 높이를 동일하게 만들고 싶을 경우 몇가지 고려할 요소가 존재한다.
구조는 대략 이러하다.

부모창
<div id="부모창의DIV">
    <iframe id="부모창의IFRAME"></iframe>
</div>

자식창
<div id="자식창의DIV">
</div>

1. contents() 
2. on load

1. contents() 
먼저 iframe에 접근하기 위해선 그냥 find로 접근하면 안된다.
contents().find()로 접근해야 한다.

$("#부모창의IFRAME").contents().find("#자식창의DIV")

2. on load
1번까지 하고 접근해보면 null을 리턴하거나 undefine을 리턴한다.
본창의 document가 ready되었을 뿐이지 iFrame의 내용까지 모두 불러와진게 아니기 때문이다.
따라서 1번 코드는 이렇게 호출되어야만 한다.
부모창의IFRAME의 contents에서 자식창의DIV란 요소를 획득하겠다란 이야기인데
언제?
iFrame이 모두 불러와져서 온전하게 자식요소들에 접근이 가능할 때 접근하겠다.

$("#부모창의IFRAME").on("load", function() {
        var objIframeChild = $("#부모창의IFRAME").contents().find("#자식창의DIV);
        $("#부모창의DIV").height(objIframeChild.height());
        /* objIframeChild로 iFrame의 자식을 획득하였으니 이녀석을 가지고 놀면 된다. 
            objIframeChild.height() 등등*/
}

여기까지 한다면 내 도메인 내에선 아무 문제 없이 주고 받고가 가능하지만
다른 도메인이라면 이야기가 달라진다.

망할 cross oigin

Uncaught DOMException: Blocked a frame with origin "http://~~~~" from accessing a cross-origin frame.
크롬에서 개발자 도구로 지켜보면 이 에러를 내뱉으며 동작하지 않는다.

iFrame 소스의 on load 또는 jQuery $(document).ready 아래에 부모로의 통신용 postMessage를 구현해준다.
구조는 간단하다.
window.parent.postMessage() 안에 {키, 값} 형태로 넣어주고 콤마(,) 이후 전달 되는 도메인이나 IP주소를 입력해주면 된다.
도메인이나 IP주소 대신 *도 가능하지만 해킹당할 우려가 있으니 가급적 지양해야 할 것이고
만약 여러 도메인으로 통신을 해야겠다면 도메인이나 IP주소만 바꿔가며 window.parent.postMessage를 반복하면 된다.

window.parent.postMessage({키값: 보내고 싶은 값 }, "허용되는 도메인 또는 아이피");

보내는 곳인 자식쪽 소스
window.parent.postMessage({ childHeight: $("자식창의DIV").height() }, "http://......");

받는 곳인 부모쪽
그냥 리스너로메세지 받겠다 하면 끝이다.
window.addEventListener('message', function(e) {
        $("#부모창의DIV").height(e.data.childHeight);
 });

반응형
Posted by Hippalus
,

반응형

웹개발을 하다보면 속도가 느려 사용을 못할 쿼리를 짜게 되기도 한다.
DB설계란게 다 그렇듯 최종 완성물로 가기까지 계속 설계가 변경되기도 하고 설령 완료되어 운영하더라도 기능 변경 요구나 데이터가 쌓여감에 따라 초기 설계와 달라지거나 속도가 느려지는 일들이 비일비재 하므로 그때마다 DBA에게 위탁하기도 뭐하고..
작은 회사에선 DBA가 있을턱도 없고 그렇다고 느린 속도를 한탄만 하고 있을 순 없는데
MSSQL에선 기특하게도 디비 튜닝을 매우 쉽게 도와주는 기능을 기본 탑재하고 있다.

초보자도 쉽게 튜닝이 가능하므로 따라해보자

1. 시퀄(mssql을 있어 보이게 발음해보자) Management Studio을 실행 후  문제가 되는 쿼리창에 복사해 두자.
2. Management Studio의 상단 메뉴에 보면 예상실행계획 표시라는 아이콘이 보일것이다. 
네모 세개가 선으로 이어지고 거기에 삼각형이 뒤집어진 아이콘인데 실행 버튼 우측에 조금만 가면 있다.
모르겠으면 단축키로 Ctrl + L을 누르면 된다.

3. 쿼리가 실행되고 나면 하단 쿼리 결과 우측에 보면 요런 ... 네모 버튼이 보일것이다.
여기에서 마우스 우측 버튼을 누르면 컨텍스트 메뉴가 나타난다.

누락된 인덱스 세부 정보(M)을 마우스 왼쪽 버튼으로 누르면

 새 쿼리창이 뜨면서 아래처럼 주석안에 누락된 인덱스를 친절히 알려준다.
/* 주석안의 */ CREATE INDEX문에서 대괄호 [] 안의 인덱스 이름을 지정해주고 실행만 시켜주면 튜닝에 필요한 적합한 인덱스가 나타난다.
<NAME OF MISSING INDEX, SYSNAME, > 이부분을 원하는 인덱스 명으로 바꿔주면 된다.
내 경우 IDX_TABLENAME_FIELD 명을 규칙으로 정해서 알맞게 바꿔주고 있다.

5. 다시 2번을 눌러서 4번까지 반복해가며 속도가 빨라질 때까지 진행하면 된다.


조건문에 따라 쿼리문이 달라지기 때문에 그에 맞게끔 쿼리를 변경해가며 수행해야 할 수도 있다.
또 인덱스를 추가만 한다고 모든 경우에 다 맞아 떨어지리란 보장 또한 없다.
경우에 따라선 설계 자체를 변경해야 할 수도 있고 쿼리 자체를 바꿔야 할수도 있지만
경험상 상당수 속도 개선 효과를 볼 수 있었다.

 

 

반응형
Posted by Hippalus
,

반응형

그냥 jQuery로 select box를 value로 변경하는건 쉬움
$("#SELECTBOX_MAIN_ID").val("1").trigger('change');

하지만 SUB selectbox가 존재하여 main selectbox가 변경되면 sub selectbox의 값도 바꿔줘야 할 경우
trigger의 change 이벤트 설정시 json형태로 key, value로 넘겨준 후
$("#SELECTBOX_SUB_ID").val("MAINVALUE").trigger('change', [{selectValue:'SUBVALUE'}]);

해당 change control의 change이벤트에 파라메터로 넘겨 받아 넘겨준 key로 받아오면 됨
$("#SELECTBOX_MAIN_ID").change(function(e, paramData {
       if (paramData != null) {
           $("#SELECTBOX_SUB_ID").val(paramData.selectValue).trigger("change");
        }
});

 

반응형
Posted by Hippalus
,

반응형

https://github.com/nitsugario/jQuery-Freeze-Table-Column-and-Rows

한번에 좌측과 헤더까지 고정시킬 때 사용하면 매우 편리한 MIT 오픈 소스
특히 colspan이 존재하게 될 경우 div로 좌측 TD column을 고정시키고자 할 경우 쉽지 않지만
이 소스를 사용하면 colspan까지 다 커버쳐줌

jQuery-Freeze-Table-Column-and-Rows-master.zip
0.07MB

사용방법은 css, js파일 그대로 복사한 후 
고정 스크롤 테이블 바깥에 DIV로 감싸고 
jQuery로 CongelarFilaColumna함수 호출할 때 몇개의 좌측 컬럼을 고정시킬것인지를 설정해주면 됨
첨부파일 중 html로 다양한 예제가 있으니 그대로 따라하면 쉽게 가능함.

다만 여러개의 테이블을 고정시켜 한 페이지에 보여줘야 할 경우 따로 테이블을 감싸고 있는 DIV의 절대 위치를 조절해줘야 함
$("#DIV_2").css({ top: $("#DIV_1").offset().top + $("#DIV_1").height() + 50 + "px" });
이런식으로 DIV_1이 처음 영역의 테이블을 감싸는 DIV이고 DIV_2가 나와야 할 경우 DIV_1의 위치와 높이값에 버퍼 50px을 주는 식으로 주면 됨

그리고 팁아닌 팁이지만
동적높이를 갖는 영역들인 경우 내 경우 700이하이면 그냥 그대로 출력하고 700이 넘으면 세로 스크롤이 나타나도록 height값을 조절해줌

가령 아래같은 구조인 경우
<div id="DIVTABLE_1">
   <table id="TABLE_1"></table>
</div>

<div id="DIVTABLE_2">
  <table id="TABLE_2"></table>
</div>

        $(".ContenedorTabla").width($("#TDCONTENT").width());
        if ($("#TABLE_1").height() < 700) {
            $("#DIVTABLE_1").height($("#TABLE_1").height());
        } else {
            $("#DIVTABLE_1").height(700);
        }

        if ($("#TABLE_2").height() < 700) {
            $("#DIVTABLE_2").height($("#TABLE_2").height());
        } else {
            $("#DIVTABLE_2").height(700);
        }

 

 

반응형
Posted by Hippalus
,

반응형

<td align="center" style="mso-number-format:\@;">

반응형
Posted by Hippalus
,