개발팁2018. 12. 26. 16:07


윈도우 OS 에서는





일정한 시간 (화면보호기 시간) 이 지나면 화면보호기(또는 바로 잠금화면)가 나타나기도 하고,

윈도우키 + L 키를 누르면, 화면잠금 기능이 바로 동작한다.

모니터상에 표시된 내용을 감추고(배경이미지를 노출하여), 로그인되어 있는 사용자의 비밀번호를 올바르게 입력해야만 잠금이 풀리게 된다.


웹에서는 자바스크립트만으로 이러한 기능을 구현할 수 있다.




구현할 기능은 아래와 같다.


1. 일정시간이 지나면, 잠금화면의 레이어가 현재 화면 위에 뜬다. (레이어 Show)

2. 또는, 특정키를 누르면 ( 여기서는 Ctrl + Alt + D 로 정의할 것이다.) 1번의 잠금상태로 전환된다.

3. 비밀번호를 올바르게 입력하면, 잠금화면이 해제 (레이어가 Hide) 

4. 브라우저의 탭을 이용하여, 같은 브라우저 세션으로 접근하더라도, 잠금 화면은 계속 유지되어야 한다. (잠금해제를 하지 않으면, 사이트를 이용할 수 없다. 또는 재로그인)


레이어 UI 는 아래와 같이 구현하였다. 사용자 개발 환경에 맞게 구현하면 되고, 예제에서는 Bootstrap 를 이용하였다.


DIV 태그는 BODY 태그 아래에 두면 된다. 파셜뷰(닷넷) 로 구현해도 된다.


class="hide" 로 인해, 평상시에는 화면에 노출되지 않다가, 잠금기능이 동작하면 (class='show'), 전체화면을 덮어버리고, 95% 로 opacity 를 채워서 기존 내용을 확인이 어렵게 하고, 로그인한 유저 이름을 표시하고, 비밀번호를 입력받게 된다.


<div id="screen-lock" class="hide" style="opacity:0.95;">

    <div class="panel panel-warning" style="width:500px;margin: 168px 0px 0px -250px;left: 50%;position: absolute;">

        <!-- begin panel-heading -->

        <div class="panel-heading">

            <h4 class="panel-title" data-i18n="message.screenlock_message">screenlock_message</h4>

        </div>

        <!-- end panel-heading -->

        <!-- begin panel-body -->

        <div class="panel-body">

            <!-- begin fieldset -->

            <fieldset>

                <!-- begin row -->

                <div class="row">

                    <!-- begin col-8 -->

                    <div class="col-md-10 offset-md-1">

                        <!-- begin form-group -->

                        <div class="form-group row m-b-10">

                            <label class="col-md-5 col-form-label text-md-right" data-i18n="label.user_name">사용자명</label>

                            <div class="col-md-6">

                                <input class="form-control" readonly value="@ViewBag.user_info.UserName">

                            </div>

                        </div>

                        <!-- end form-group -->

                        <!-- begin form-group -->

                        <div class="form-group row m-b-10">

                            <label class="col-md-5 col-form-label text-md-right" data-i18n="label.password">비밀번호</label>

                            <div class="col-md-6">

                                <input type="password" id="lock_Password" class="form-control" />

                            </div>

                        </div>

                        <!-- end form-group -->

                    </div>

                    <!-- end col-8 -->

                    <div class="icon" style="padding-top: 5px;position: absolute;padding-left: 35px;">

                        <i class="fa fa-unlock fa-5x" style="color:#919191;"></i>

                    </div>

                    <div class="panel-footer" style="width:100%;text-align: center;">

                        <button id="LockPasswordCheckAction" class="btn btn-success" data-i18n="label.unlock">unlock</button>

                        <button class="btn btn-white LogoutAction" data-i18n="common.logout">logout</button>

                    </div>


                </div>

                <!-- end row -->

            </fieldset>

            <!-- end fieldset -->


        </div>

        <!-- end panel-body -->

    </div>

    <!-- end panel -->

</div>




이제 스크립트로 일정시간이 지났을때, 특정키를 눌렀을때, 잠금 화면을 노출할것이다.


screenlock.initLock = function() {


    screenlock.timerHandle = window.setTimeout(function () {

        screenlock.setLock();

    }, 30 * 1000 * 60); // 30분 경과시 잠금처리


 

    // Ctrl + Alt + L 키를 누려면 강제 잠금 모드로 전환한다.

    $("body").keydown(function (event) {

        if (event.ctrlKey && event.altKey && event.keyCode == 76) {

            screenlock.forceLock();

        }

    });


}


// 강제잠금 기능

screenlock.forceLock = function () {

    // 잠금처리

    $.cookie(screenlock.cookieName, 1, { path: '/' });


    $('#screen-lock').removeClass("hide");

    $('#screen-lock').addClass("show");

}




공통으로 호출되는 VIEW화면(html) 에서, (닷넷에서는 레이아웃에서 호출하면된다.)


$(document).ready() 에서 initLock() 를 호출해 주면된다.


일단은, screenlock.setLock 과 screenlock.forceLock 은 똑같이 구현해 준다.


30분이 흐르거나, Ctrl + Alt + L 키를 누르면, 잠금 화면이 나올것이다.


$.cookie(screenlock.cookieName, 1, { path: '/' });


쿠키에 값을 쓰는 이유는,


한번 잠금 상태일경우, 페이지 새로고침이나, 브라우저의 TAB 으로 접근하였을때, 쿠키값을 참고하여, 계속 잠금 상태를 유지하도록 하기 위함이다. (아래에서 구현)



잠금해제는, AJAX 요청으로 서버에서 비밀번호 검증하고 검증이 통과 하였을경우,


아래 코드를 실행해주면된다.


$.removeCookie(screenlock.cookieName, { path: '/' });

window.clearTimeout(screenlock.timerHandle);

// $.removeCookie(screenlock.initCookieName, { path: '/' }); // initCookieName 는 아래에서 다시 설명할 것이다.


$('#screen-lock').removeClass("show");

$('#screen-lock').addClass("hide");



잠금 기능과 해제 기능이 구현이 되었다면, initLock 을 아래와 같이 변경해보자.



screenlock.initLock = function () {

    let isLocked = $.cookie(screenlock.cookieName) != undefined;


     if (isLocked) {

        $('#screen-lock').removeClass("hide")

        $('#screen-lock').addClass("show")

    }

    else {

        screenlock.resetLock();

    }


    // Ctrl + Alt + L 키를 누려면 강제 잠금 모드로 전환한다.

    $("body").keydown(function (event) {

        if (event.ctrlKey && event.altKey && event.keyCode == 76) {

            screenlock.forceLock();

        }

    });


    return isLocked;

}


screenlock.resetLock = function () {

    // timeout 시간을 재설정한다.


    if (screenlock.timerHandle != undefined) {

        window.clearTimeout(screenlock.timerHandle);

    }


    $.cookie(screenlock.initCookieName, (new Date()).getTime(), { path: '/' });


    screenlock.timerHandle = window.setTimeout(function () {

        screenlock.setLock();

    }, 30 * 1000 * 60);

}


여러개의 TAB 을 사용할경우, 하나의 탭에서 잠금상태로 전환되면, (쿠키에 저장하여) 잠금상태를 계속 유지하게 되고,


또한, 여러개의 TAB 에서 1개의 TAB 에서 계속 사용하고 있으면, 나머지 TAB 이 잠기는것을 방지하기 위해,


initCookieName 을 쿠키에 저장할 것이다. 쿠키값은 현재 시간의 timestamp 값이다.


이 값을 사용하여, window.setTimeout 으로 지정된 시간이 지났더라도, 잠기지 않도록 구현할 것이다.


이제, screenlock.setLock 함수를 아래와 같이 다시 재정의 한다.


screenlock.setLock = function () {

    let initTime = $.cookie(screenlock.initCookieName);


    // 쿠키에 저장된 init 날짜를 비교하여, 시간이 경과한경우만, 잠금처리한다.

    // 창을 여러개 띄어놓고 작업할경우, 사용하지 않는 창에서 무조건 락이 걸리는 문제를 해결하기 위해 사용.

    if (initTime != undefined) {

        let curTime = (new Date()).getTime();


        let diff_min = (curTime - parseInt(initTime)) / 1000 / 60 * 1.1; // 10% 오차범위로 처리한다. * 1.1


        //console.log('diff_min', diff_min);


        if (diff_min < screenlock.lockTime) {

            screenlock.resetLock(screenlock.lockTime / 5);  // 1/5 간격으로 다시 검사하도록 한다.


            return;

        }

    }


    // 잠금처리

    screenlock.forceLock();

}



위의 코드는 window.setTimeout 을 사용하여, 30분이 지나면, 잠금기능이 동작하게 되어 있다.



화면이 새로고침 된다면, 이 시간은 다시 셋팅 (resetLock 함수) 이 되기 때문에, 문제가 없는 것처럼 보인다.


하지만 SPA (Single Page Application) 이나, 한 화면안에서 AJAX 요청으로 오래 작업을 하는 경우가 있다면, 사용중에 화면이 잠기는 문제가 있다.


사이트를 사용중일때는 (윈도우 사용이랑 별개) 잠기지 않게 해주어야 한다.


페이지 새로고침없는 상태에서도, 사이트를 사용중이라는 것에 대한 정의가 필요하다.


ex) AJAX 요청이 있다거나, key 를 누른다거나..


key 누르는 이벤트에 대헤서는 아래코드를 initLock 에서 구현할 수 있다.


$("body").keydown(function (event) {

      screenlock.resetLock();

});


이를 이용하여, mouse move 또는 mouse down 이벤트에 대해서도 구현이 가능하다.


두번째는 ajax 요청에 대한 처리이다.

$.ajax 를 이용한다면, $.ajaxSetup 에서 공통 옵션과 콜백함수를 정의할 수 있다. 


$.ajaxSetup({


    beforeSend: function (xhr) {


            if (this.url.indexOf("PasswordCheck") < 0) // 화면잠금에서 비밀번호 체크할때는 제외한다.

                screenLock.resetLock(); // 서버로 AJAX 요청이 올때마다, 화면잠금시간을 연장한다.

    }

});


이제 모든 기능이 구현되었다.



위에서는 잠금상태를 위한 초기 timestamp 값이랑, 잠금상태값을 쿠키에 저장하였지만,

쿠키는 매번 서버로 전송되기 때문에, 불필요한 값이 서버에 전송되기도 한다.


SessionStorage 로 변경도 가능하다.


Posted by 헝개
책책책2018. 12. 24. 18:38

살인자의 기억법

 

 

 

 

알쓸신잡에서 박학다식한 작가를 맡았던, 김영하 작가의 소설이다.

 

 

 

 

유명한 소설가이다, 알쓸신잡에서는 굉장히 머리도 좋은 사람인것 같다.

 

그러나, 그의 책은 살인자의 기억법이 처음이다.

사실, 살인자의 기억법도 영화로 먼저 접하게 되었고, 그의 책이 원작인것도 모를 정도이니... 뭐...

 

아무튼, 연쇄살인마가 알츠하이머에 걸려서 기억을 잃어버린다면 어떻게 될까하는 작은 호기심에서 부터

이 책이 시작되었으리라 본다.

 

 

무시무시한 연쇄살인마에게도 지켜야할 가족이 있고, 자식이 있다면...

과거의 싱싱한 뇌가 기억하는 연쇄살인은 기억을 하는데,

현재의 늙은 뇌가 메모리한 최근의 기억은 점점 사라져 간다면....

 

 

영화는 개봉판과 감독판이 있는데, 전혀 다른 결말을 주고 있다.

이 책은 후자인 감독판에 가깝다고 볼 수 있다.

 

 

작가는 굉장히 책도 많이 읽고 박학다식한 사람인것이 책에 드러난다.

책을 읽음으로 자연스레 작가의 유식함이 드러나는것은 아니고, 드러내놓고 나 이렇게 책도 많이 읽고 아는것도 많은 사람이야! 라고 말하는것 같은 느낌이랄까..

 

작가는 이 책에서 장면 장소의 미장센을 디테일하게 설명하지 않고 있다.

 

알츠하이머에 걸린 늙은이의 시각으로 글이 쓰여진다.

시간의 흐름을 타고 진행이 되면서, 과거의 기억들을 끄집어 내고 있다.

 

이야기는 온전히 1인칭 연쇄살인마의 기억과 기록 시각에 따라 진행이 된다.

 

그에게는 지켜야 할 딸이 하나 있고, 그 딸을 노리는 젊은 살인마가 등장한다.

늙고, 기억도 가물가물하는 주인공은, 과연, 젊은 살인마로부터 딸을 지켜낼 수 있을까?

 

아뿔사, 화자인 주인공이 알츠하이머이다.

하루하루, 아니 몇시간전의 기억조차 까먹는 사람이다.

그가 이야기를 이끌어 가는데, 그의 이야기를 다 믿을 수가 없다는걸 깜박했다.

 

작가는, 결말에 지금까지의 이야기가 다 거짓이라고 말하고 있다.

책을 각색한 영화의 스토리가 오히려 더 앞뒤가 맞고, 잘 짜여졌다.

물론, 책과 영화의 이야기 전개는 거의 대부분이 비슷하다.

 

 

알츠하이머, 기억상실자가 거짓말쟁이가 된다는 결론은 어쩌면, 개의 목줄을 잡고, 작가가 가고 싶은곳으로 억지로 끌고 가는것이 아닌가 한다.

 

알츠하이머 라면, 최근의 기억들에서부터 점차, 기억들이 삭제되어 과는 과정을 그리면 어땠을까..

70대의 노인이지만, 기억이 삭제되면서, 점차 60대, 50대, 40대, 30대로 돌아가서,

본인이 아직도 연쇄살인마라고 착각을 하여, 살인을 시도하려는 과정..

그러나 이미 몸은 늙어서, 살인이 성공하기는 어렵게 되는 과정이 더 설득력이 있지는 않을까..

 

 

'책책책' 카테고리의 다른 글

고양이, 베르나르베르베르  (0) 2019.01.28
그 후에, 기욤 뮈소  (0) 2019.01.22
눈먼 자들의 도시, 주제 사라마구  (0) 2019.01.13
신, 베르나르 베르베르  (0) 2019.01.07
채식주의자, 한강 작가  (0) 2019.01.06
Posted by 헝개
개발팁2018. 12. 19. 10:29

자바스크립트의 데이터타입에 따라, 숫자는 0으로 초기화 하고, 문자열은 "" 으로 초기화 한다던가 할 수 있다.

 

json 객체는 그 안에, 숫자,문자,배열,함수,nested 객체 등의 여러 형식을 포함 할 수 있다.

 

 

jquery 의 $.each 를 통해서, 객체 개개의 항목에 접근할 수 있고,

 

또 자바스크립트의 typeof 를 통해, 각 항목의 데이터 타입을 알아낼 수 있다.

 

 

typeof 로 알아 낼 수 있는 데이터타입은 6가지가 있다.

 

"number", "string", "boolean", "object", "function", "undefined"


참고 : https://msdn.microsoft.com/ko-kr/library/259s7zc1(v=vs.94).aspx

 

jquery 에서도 typeof 와 비슷한 함수를 제공하는데,

 

 

$.type 을 이용하면, typeof 의 6가지 외에,

 

"null", "array", "date", "error", "symbol", "regexp" 등의 형식도 알 수 있다.

 

참고 : https://api.jquery.com/jQuery.type/

 

 

실제로, typeof 에서는 대부분 object 로 구분하는 형식에 대해서, $.type 은 상세한 형식을 알려주는 것을 볼 수 있다.

 

typeof([])
"object"

 

$.type([])
"array"

 

typeof(null)
"object"

 

$.type(null)
"null"

 

typeof(/test/)
"object"

 

$.type(/test/)
"regexp"

 

 

이제, $.each 와 $.type 을 이용하여, object 를 초기화 하는 함수를 만들 수 있다.

 

$.ObjectInitialize = function (obj) {


    let self = this;
    self.obj = obj;

 

    $.each(obj, function (item_name, item) {


        let datatype = $.type(item);

 

        if (datatype == "number")
            self.obj[item_name] = 0;   // 정수는 0 으로 초기화


        else if (datatype == "string")
            self.obj[item_name] = '';   // 문자는 '' 으로 초기화


        else if (datatype == "boolean")
            self.obj[item_name] = false;   // boolean 는 false 으로 초기화


        else if (datatype == "array")
            self.obj[item_name] = [];   // 배열은 [] 으로 초기화


        else if (datatype == "object")
            self.obj[item_name] = {};   // object는  {} 으로 초기화


    });

 

 

 

배열은 [] 으로 초기화 하고, object 는 {} 으로 초기화 하고 있다.

 

a = { x:10, y:"10", z: { k:10, l:"abcd" } };

 

$.ObjectInitialize(a);

 

 

 

 

위에서는 nested object 를 처리하지 않고 있지만, 중첩 객체도 다시, 초기화를 할 수 있다.

 

$.ObjectInitialize = function (obj, deep) {


    let self = this;
    self.obj = obj;

 

    $.each(obj, function (item_name, item) {


        let datatype = $.type(item);

 

        if (datatype == "number")
            self.obj[item_name] = 0;   // 정수는 0 으로 초기화


        else if (datatype == "string")
            self.obj[item_name] = '';   // 문자는 '' 으로 초기화


        else if (datatype == "boolean")
            self.obj[item_name] = false;   // boolean 는 false 으로 초기화


        else if (datatype == "array")
            self.obj[item_name] = [];   // 배열은 [] 으로 초기화


        else if (datatype == "object") {
            if (deep)   // deep 적용 : object 를 다시 $.ObjectInitialize 를 호출하여 초기화 한다.
                $.ObjectInitialize(self.obj[item_name]);
            else
                self.obj[item_name] = {};   // object는  {} 으로 초기화
        }


    });

 

 

deep 옵션에 따라 nested objet 도 초기화 하도록 변경을 했다.

 

 

 

a = { x:10, y:"10", z: { k:10, l:"abcd" } };

 

$.ObjectInitialize(a, true);

 

 

 

Posted by 헝개
개발팁2018. 12. 14. 16:02

Vue Component 간의 통신하기 위한 방법으로 Event 를 발행하고, Event 를 구독하는 방법을 이용할 수 있다.

 

Vue 이벤트에는 전역이벤트 또는 Global 이벤트가 있고, Component 이벤트 가 있다.

 

 

1. 전역이벤트

 

EventBus 를 통해, 발행하고, 구독할수 있으며,

 

블특정 컴포넌트에서 발행한 이벤트를 구독할 수 있는 형태이다.

 

 

공통의 script 파일안에 전역으로 아래와 같이 선언한다.

 

var EventBus = new Vue();

 

 

EventBus 는 단지, Vue 객체이다.

 

이벤트 발행

 

EventBus.$emit('이벤트명', 전달할 데이터...);

 

이벤트 구독

 

EventBus.$on('이벤트명', function(전달받을 데이터...) { } );

 

사용예제)

 

1. 이벤트발행시

EventBus.$emit("log_class_request", self, findTab.LogClass);

 

2. 이벤트 구독시

EventBus.$on('log_class_request', function (sender, LogClass) {
                self.filter_LogClass = LogClass;
            }); 

 

 

 

2. Component 이벤트

 

컴포넌트 이벤트는 일반적인 언어에서의 이벤트 사용방법과 동일하다.

 

특정 컴포넌트 안에서 이벤트를 발생시키면,

 

해당 컴포넌트를 호출한 부모객체에서 이벤트를 구독하는 방식이다.

 

이벤트 발행

 

this.$emit('이벤트명', 전달할 데이터...);

 

이벤트 구독

 

컴포넌트객체명.$on('이벤트명', function(전달받을 데이터...) { } );

 

 

 사용예제)

 

1. 이벤트발행시

this.$emit('hero_selected', selected_data);

 

2. 이벤트 구독시

self.$children.hero_select = Hero.Select.init(self);  // 컴포넌트 생성


self.$children.hero_select.$on('hero_selected', function (data) {
   ............

});

 

 

Posted by 헝개
개발팁2018. 12. 14. 15:39

data: {

     my_object: {}

} 


 

this.$data.my_object.col1 = "";

this.$data.my_object.col2 = "";

 

위와같이 중첩된 데이터에 컬럼을 추가 하게 되면, my_object  Observable 데이터이지만,

col1, col2  Observable 데이터가 아니다.



콘솔 로그로 확인해보면,



$data 를 확인해보면, my_object 는 observer 로 되어 있는걸 확인할 수 있다.

get my_object / set my_object 라는 property 가 자동으로 생성이 된것이다.


하지만, my_object 를 펼쳐보면, col1, col2 에는 아무것도 없다.


즉, col1, col2 는 vue 의 반응형 데이터로 동작하지 않는다는 것이다.




nested object 에 반응형 데이터를 추가하기 위해서, Vue.set 문장으로 바꾸어 보자.


Vue.set(this.$data.my_object, 'col1', '');

Vue.set(this.$data.my_object, 'col2', '');

 


다시, 콘솔 로그로 확인해보자.





my_object 안에 col1, col2 모두 observable 데이터로 등록이 된것을 확인할 수 있다.



 

Posted by 헝개
개발팁2018. 11. 7. 12:40

ajax 는 말그대로, 비동기 통신을 하기 위한, 도구이다.


jquery 에서는 $.ajax 또는 jQuery.ajax 라는 메서드를 통해서, 쉽게 ajax 를 이용할 수 있다.


내부적으로는 XMLHttpRequest 를 이용하고 있으며, 여러가지 편의 기능, option 을 제공하고 있다.


이중에서도, 매번 ajax 로 요청할때, 동일하게 사용하는 option / 처리가 끝나고 결과에(response) 대해 성공/실패/항상 처리해야 할일을 


$.ajaxSetup 에 미리 정의해 놓으면, 코드양도 줄여주고, 간결해지게 된다.



여기서 다룰 내용은, $.ajax 요청이 비동기(asyncronous) 요청이기 때문에, 이를 위해, promise 처리를 하는 방법이다.


기본적으로, $.ajax 요청의 결과를 받는 방법으로 많이 사용되는것이,


complete


success


error


ajax 요청이 완료되고 결과(response) 가 나오면, 우선적으로, complete 에 정의된, 함수 (또는 콜백함수) 가 실행이 된다.


그리고 나서, 결과가 http 오류인지 http 성공(200 ok) 인지에 따라, success / error 에 정의된 함수 (또는 콜백함수) 가 실행이 된다.


이 방식은, 비동기 요청(ajax) 를 하고 나서, 처리결과에 따라, 다음 작업을 진행해야 할때마다, 매번 callback 함수를 사용해야 하는 문제를 발생시킨다. (불편한 코드의 문제...)


다행이도, $.ajax 는 위의 함수(또는 콜백함수) 기능외에 Promise 패턴이 적용되어 있다. (jquery  의 deferred 로 구현됨)



$.ajax({ url : '/post/url', data: 'param, ... } ).then( function(result, status, responseObj) {

성공일때 내용...

}, function (result, status, responseObj) {

실패일때 처리할 내용...

});


위와 같이 코드를 작성할 수 있다, 뒤의 실패일때의 function 부분은 생략도 가능하다.


이 코드는 다시 아래와 같은 형태로 변경이 가능다.


$.ajax({ url : '/post/url', data: 'param, ... } ).done( function(result, status, responseObj) {

성공일때 내용...

}).fail(function (result, status, responseObj) {

실패일때 처리할 내용...

});


then() 은 done(), fail() 로 분리해서 처리할수 있다.

성공/실패 여부와 상관없이 항상 실행해야 할 코드는 always() 에 넣어줄 수 있다.

 $.ajax({ url : '/post/url', data: 'param, ... } ).done( function(result, status, responseObj) {


성공일때 내용...


}).fail(function (result, status, responseObj) {


실패일때 처리할 내용...


}).always(function (result, status, responseObj) {


항상 처리할 내용...


});



done() 이나 fail() 이 먼저 실행되고 난 후에 always 가 실행이 될것이다.



여기서 주의할 점은, $.ajax 의 promise 패턴은 http response 의 성공(200 ok) 이냐 실패냐에 기인한다는 점이다.

이는, 논리적인 성공 실패가 아니라, 물리적인 성공/실패를 의미하는 것이다.




웹서버에서 오류가 났을때, http 오류가 아니라, 적당한 오류 코드 와 오류 메세지를 response 해준다면, 어떨까?


그렇다면, $.ajax 는 이를 성공으로 간주하게 되어, 성공(done) 에서 논리적인 오류인지를 체크해야 한다.




이를 간소화 하기 위해서 아래와 같이 $.ajax 에 또다른 Promise 패턴을 적용한 래퍼함수(Wrapper) 를 만들 수 있다.


jquery 에서는 promise 패턴을 구현하기 위해, $.Deferred 라는 것을 제공하고 있다.


(실제 promise 패턴을 이용하기 위해 Promise 객체가 있지만, IE 에서는 지원하지 않기때문에, 호환성을 위해, $.deferred 를 사용했다.)



성공, 실패에 대해서는, resolve / reject 함수를 제공하며, 결과는 promise() 를 리턴해주면 된다.


$.ajax.promise = function (options) {

    var deferred = $.Deferred();


    $.ajax(

        options

    ).done(function (result, status, responseObj) {

        if (!result.bSuccess)    // failed

        {

            deferred.reject(result, status);

            return;

        }


        //data = JSON.parse(result.sJsonData);

        data = ( result.sJsonData == null || result.sJsonData == "" ) ? null : JSON.parse(result.sJsonData);


        deferred.resolve(result, data);

    }).fail(function (result, status, responseObj) {

        deferred.reject(result, status);

    });


    return deferred.promise();

}



이 코드의 전제는 json 데이터를 받는다는 점이고, result 에 bSuccess 라는 속성이 존재한다는 점이다.


$.ajax 의 래퍼함수인 $.ajax.promise 를 이용하여, 위의 $.ajax promise 이용 예를 다시 호출해보면 아래와 같다.


 $.ajax.promise({ url : '/post/url', data: 'param, ... } ).done( function(result, data) {


성공일때 내용...


}).fail(function (result, status, responseObj) {


실패일때 처리할 내용...


}).always(function (result, status, responseObj) {


항상 처리할 내용...


});



이제, 위 코드의 성공/실패 코드는 물리적인 http 오류외에도, 논리적인 오류에도 대응되는 코드로 변경이 된다.


위 코드는 단일 ajax 코드를 실행하는 방법이고, jquery 에서는 여러개의 promise 패턴을 처리하는 방법으로,


$.when 이라는 함수를 체공한다.



var pr1 =  $.ajax.promise({ url : '/post/url', data: 'param, ... } );

var pr2 =  $.ajax.promise({ url : '/post/url', data: 'param, ... } );

var pr3 =  $.ajax.promise({ url : '/post/url', data: 'param, ... } );


$.when(pr1, pr2, pr3).done(function() {

      모두 성공일때...

});

비동기 메서드이기 때문에, 위의 3줄은 같은 시기에 실행이 되지만, 결과는 제각각 다르게 나올것이다.

하지만, 모든 실행이 끝나고 나서, 처리해야할 내용이 있을때,

done() 함수에 넣어주면 된다.


$.when 도 promise 패턴으로 구현되어 있기 때문에,


done / fail / then 모두 사용가능하다.



Posted by 헝개
개발팁2018. 11. 7. 11:58

자바스크립트에서 다국어 지원을 위한, 라이브러리로 i18n 을 사용하다면,


다국어 text 정의는, 언어 key 와 언어 text 쌍의 json 파일로 관리가 된다.


i18n.t('key.key2.key3')


특정 key 를 현재 언어의 다국어 text 로 변환할때, 위와 같이 javascript 에서 사용하거나,


<span data-i18n='key.key2.key3'></span>


위와 같이 태그 안에서 직접 key 를 호출할 수 있다.



만약, 현재언어의 key.key2.key3 라는 키가 없다면, 대체 text 가 출력되거나, 기본 언어(default language) 의 key 를 찾아서, text 를 출력하게 된다.



누락된 key 가 있는지, 각 언어마다 빠진 데이터가 있는지를 찾아내기는 힘든일이다.


이때, 누락된 데이터가 나오면, 자동으로 알려준다면, 얼마나 쉽게 빠진 text 를 추가할 수 있겠는가..


i18n의 sendMissing 이라는 기능을 이용하면, 쉽게 누락데이터를 관리할 수 있다.



i18n 초기화 함수인 $.i18n.init 의 option 으로 아래와 같은 코드를 작성하면 된다.



        sendMissing: true,              // 번역데이터가 없을때 서버에 전송한다.

        sendMissingTo: 'fallback',

        resPostPath: '/System/I18nMissingKey_Insert'    // 번역데이터가 없을때 서버에 POST 로 넘겨주는 URL


위의 코드 의미는, 누락데이터가 발생했을떼, 웹서버의 /System/I18nMissingKey_Insert 주소로 POST (포스팅) 을 하게 된다.


웹서버는 닷넷이든 자바이든 상관없이, form 방식의 post 데이터를 받아서 처리하면 된다.


실제 서버로 전송되는 데이터는 name / value 의 form data 이고, 아래와 같은 형태이다.


key1.key2.key3=기본text


FORM 데이터의 name 값이 정해진 값이 아니라, key 값을 그대로 전송하기 때문에, form 객체에서 첫번째 항목을 읽어서 처리하면 되겠다.


실제 ASP.NET MVC 에서 Form ModelBinder 로 받아서 첫번째 항목을 DB 에 저장하는 소스이다.

사용하는 언어에 맞게 코딩하면 된다.



        [HttpPost]

        public JsonResult I18nMissingKey_Insert([ModelBinder(typeof(FormRequestModelBinder))] JObject reqParam)

        {

            dynamic param = new

            {

                TKey = ((Newtonsoft.Json.Linq.JProperty)(reqParam.First)).Name, // Request 값중에 첫번째 값을 가져온다.

                DefaultValue = reqParam[((Newtonsoft.Json.Linq.JProperty)(reqParam.First)).Name].ToString(),

                LangCode = this.GetCurrentLang()

            };


            SpotResult result = (new Biz_I18nMissingKey()).Insert(param);


            return Json(result);

        } 

 



아래 화면은 실제 DB 에 저장된, 누락데이터를 조회하고, 등록하는 기능이다.

각 언어별 json 파일로 분리해서 저장하고 있다.




위 코드는 누락된 i18n 데이터만을 관리하고 있지만,


실제, i18n 으로 번역 key / text 를 각각의 json 파일로 관리하는것은 쉽지가 않다.


이를 편하게 관리하기 위해, 각각의 json 파일을 merge 해서, 하나의 datatable 로 관리하도록 한 화면이다.




Posted by 헝개
맛집2018. 10. 3. 18:50

신당역과 청구역 중간쯤에 위치하고 있습니다.

 

메뉴판에는 한우구이인데, 와규라고 적혀있고 해서, 한우인지 와규인지는 잘 모르겠네요. ㅋㅋ

 

이름이 양념이네 라고, 아주 특이한 이름으로 지었네요.

양념이는 아마 이집에 사는 개이름이 아닐까 합니다. ㅋㅋ

 

 

 

 

 

 

 

메인메뉴에는 와규로 나와 있는데,

 

 

 

여기에는 또, 한우구이 * 수제꼬치 요리주점 이라고 나와 있네요.

 

 

 

 

요게 기본 셋팅입니다.

 

 

 

고기랑 꼬치랑 따로 시켜도 되고, 세트를 시킨다음에 모자라면 추가로 시켜도 됩니다.

 

 

 

 

 

불판이 일본식으로 작은 화로 입니다.

소고기라 빨리 익어서, 2명이서 먹기에는 딱 적당한 사이즈입니다.

 

한우인지 와규인지 아무튼 소고기는 맛있습니다.

 

 

 

Posted by 헝개
음악2018. 10. 3. 18:22

거침없이 하이킥의 야동순재 테마곡 사랑은 개나소나

 

 

극중에서는, 유미(박민영)의 엄마(이경미) 님의 앨범으로 나오는데,

실제로도, 이경미님의 노래이네요.

 

가사가 너무 재미있고, 뒤에 반복되는 후크송이 중독성이 있네요.

 

 

 

개는 반갑다고 꼬리나 치지
소는 음메음메 울수나 있지
나는 바보라 당신 잡지도 못해
LA로 훌쩍 가버린 당신~


사랑은 개나소나 다한다지만
나는 개소만도 못한 바보야-
사랑은 개나소나 다한다지만
나는 개소만도 못한 바보야-
사랑은 개나소나 다한다지만
나는 개소만도 못한 바보야-
사랑은 개나소나 다한다지만
나는 개소만도 못한 바보야~

사랑은 개나소나 다한다지만
나는 개소만도 못한 바보야
사랑은 개나소나 다한다지만
나는 개소만도 못한 바보야

 

 

 

'음악' 카테고리의 다른 글

공일오비 (015B) 2집 - 1991.05 발매  (0) 2020.04.06
변진섭 2집 - 1989.10.25 발매  (0) 2020.04.05
김민종 1집 - 1992.03.30 발매  (0) 2020.04.04
김민종 비  (1) 2016.06.24
투투 김지훈의 그대 눈물까지도  (1) 2016.06.04
Posted by 헝개

1UP PIX 가 액정이 2.2인치라서, 게임목록의 글짜가 상당히 작습니다.

 

폰트 사이즈는 총 3종류가 있습니다.

 

기본사이즈, 대, 특대

 

https://www.qoo10.com/g/617871938/Q107829067

 

위에 qoo10 에서 메모리포함으로 구입한 1UP PIX 만 폰트사이즈 변경이 가능하니다.

 

PRO 업데이터를 통해 변경하였습니다.

 

레트로박스(1UP PIX) 버전확인은, 게임기 선택화면 오른쪽 하단에 표시됩니다.
버전 표시가 없으면, 정품이 아니라 업데이트 서비스를 받을 수 없습니다.

 

 

 

아래 순서대로 기본사이즈, 대, 특대 입니다.

 

 

 

 

 

 

 

Posted by 헝개