블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함

calendar

          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            


프로젝트를 진행하다 보면 여러 요청 사항들이 이루어 지도록 구현해야 하는 상황이 많이 있지요.


그 중에서는 별로 구현해 봤자 크게 유용하지 않은 것들도 있습니다. 프로그래머 입장에서 봤을 때 말이죠.


이번에 jQuery Mobile 프로젝트를 진행하는데 그래픽 디자이너가 아래 와 같이 만들어 버렸습니다.




음 이건....


왼쪽의 arrow button 이 문제인데요. 왜냐하면 jQuery Mobile 에서는 저런 arrow button 을 지원하지 않거든요. 저런 버튼은 iPhone 이나 iPad 같은 iOS 기기에서 지원하는 위젯이거든요.



아마 디자이너가 아이폰에서 저런 arrow-back button 을 보고 디자인을 한 것 같습니다.

일단 저런 요청이 들어왔으니까 저는 한번 시도해 보기로 했습니다.

jQuery Mobile 에서 arrow button 구현하기.


아래 버튼이 제가 구현한 것인데요.




CSS 로 긴 사각형을 만들고 왼쪽에 작은 사각형을 만든 다음에 이걸 45도 돌린 겁니다.

여기서 작은 사각형을 돌리고 나서 오른쪽에 있는 버튼이랑 잘 어울려야 하거든요.

그래서 Gradient 를 45도 rotate 하고 난 상태에서 오른쪽 사각형이랑 어울리도록 하는 것이 관건입니다.




<html>
<head>
<style type=text/css>
#ios-arrow-left {
    display : block;
    position:absolute;
    z-index : 0;
    left:50px;
    top:50px;   
    height:30px;
    width:100px;
    padding: 0 10px 0 6px;

    font-weight:
            bold;
    color:
            #fff /*{f-bup-color}*/;
    text-shadow:
            0 /*{f-bup-shadow-x}*/
            1px /*{f-bup-shadow-y}*/
            0 /*{f-bup-shadow-radius}*/
            #294d05 /*{f-bup-shadow-color}*/;
           
    border-radius: 5px;

    background:
        #b9f07f; /* Old browsers */
    background:
        -moz-linear-gradient(
            top, 
            #b9f07f 0,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* FF3.6+ */
    background:
        -webkit-gradient(
            linear,
            left top,
            left bottom,
            color-stop(0,#b9f07f),
            color-stop(9%,#8fbd36),
            color-stop(94%,#387800),
            color-stop(97%,#74a814),
            color-stop(100%,#387800)); /* Chrome,Safari4+ */
    background:
        -webkit-linear-gradient(
            top, 
            #b9f07f 0,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* Chrome10+,Safari5.1+ */
    background:
        -o-linear-gradient(
            top, 
            #b9f07f 0,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* Opera 11.10+ */
    background:
        -ms-linear-gradient(
            top, 
            #b9f07f 0,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* IE10+ */
    background:
        linear-gradient(
            to bottom, 
            #b9f07f 0,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* W3C */
           
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b9f07f', endColorstr='#387800',GradientType=0 ); /* IE6-9 */
}

#ios-arrow-left:before {

    position:absolute;
    content : ' ';
    left:-7px;
    top:4px;
    height : 21px;
    width: 20px;
    z-index : 1;

    -moz-transform :
        rotateZ(45deg) skewY(-0deg) skewX(-0deg);
    -o-transform :
        rotateZ(45deg) skewY(-0deg) skewX(-0deg);
    -webkit-transform :
        rotateZ(45deg) skewY(-0deg) skewX(-0deg);
    transform :
        rotateZ(-0deg) skewY(-0deg) skewX(-0deg);
   
    background: #b9f07f; /* Old browsers */
    background:
        -moz-linear-gradient(
            -45deg, 
            #b9f07f 0%,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* FF3.6+ */
    background:
        -webkit-gradient(
            linear,
            left top,
            right bottom,
            color-stop(0%,#b9f07f),
            color-stop(9%,#8fbd36),
            color-stop(94%,#387800),
            color-stop(97%,#74a814),
            color-stop(100%,#387800)); /* Chrome,Safari4+ */
    background:
        -webkit-linear-gradient(
            -45deg, 
            #b9f07f 0%,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* Chrome10+,Safari5.1+ */
    background:
        -o-linear-gradient(
            -45deg, 
            #b9f07f 0%,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* Opera 11.10+ */
    background:
        -ms-linear-gradient(
            -45deg, 
            #b9f07f 0%,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* IE10+ */
    background:
        linear-gradient(
            135deg, 
            #b9f07f 0%,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* W3C */
    filter: progid:
        DXImageTransform.Microsoft.gradient(
            startColorstr='#b9f07f',
            endColorstr='#387800',
            GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
}

#ios-arrow-left:hover {
    background:
            #b9007f /*{f-bup-background-color}*/;
    border:
            1px solid #5f666b /*{f-bup-border}*/;
    background:
            #b9f07f /*{f-bup-background-color}*/;
    font-weight:
            bold;
    color:
            #fff /*{f-bup-color}*/;
    text-shadow:
            0 /*{f-bup-shadow-x}*/
            1px /*{f-bup-shadow-y}*/
            0 /*{f-bup-shadow-radius}*/
            #294d05 /*{f-bup-shadow-color}*/;
    background:
            #387800; /* Old browsers */
    background: -moz-linear-gradient(
            top, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* FF3.6+ */
    background: -webkit-gradient(
            linear,
            left top,
            left bottom,
            color-stop(0%,#387800),
            color-stop(9%,#74a814),
            color-stop(94%,#387800),
            color-stop(100%,#b9f07f)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(
            top, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(
            top, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(
            top, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* IE10+ */
    background: linear-gradient(
            to bottom, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* W3C */
    filter: progid:DXImageTransform.Microsoft.gradient(
            startColorstr='#387800',
            endColorstr='#b9f07f',
            GradientType=0 ); /* IE6-9 */
}

#ios-arrow-left:hover:before
{

    position:absolute;
    content : ' ';
    left:-9px;
    top:4px;
    height : 21px;
    width: 20px;
    z-index : 1;

    -moz-transform :
        rotateZ(45deg) skewY(-0deg) skewX(-0deg);
    -o-transform :
        rotateZ(45deg) skewY(-0deg) skewX(-0deg);
    -webkit-transform :
        rotateZ(45deg) skewY(-0deg) skewX(-0deg);
    transform :
        rotateZ(-0deg) skewY(-0deg) skewX(-0deg);
       
        border-bottom:
            1px solid #5f666b;
        border-left:
            1px solid #5f666b;           

   
    background: #387800; /* Old browsers */
    background:
        -moz-linear-gradient(
            -45deg, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* FF3.6+ */
    background: -webkit-gradient(
            linear,
            left top,
            left bottom,
            color-stop(0%,#387800),
            color-stop(9%,#74a814),
            color-stop(94%,#387800),
            color-stop(100%,#b9f07f)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(
            -45deg, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* Chrome10+,Safari5.1+ */
    background:
        -o-linear-gradient(
            -45deg, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* Opera 11.10+ */
    background:
        -ms-linear-gradient(
            -45deg, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* IE10+ */
    background:
        linear-gradient(
            -45deg, 
            #387800 0%,
            #74a814 9%,
            #387800 94%,
            #b9f07f 100%); /* W3C */
    filter: progid:
        DXImageTransform.Microsoft.gradient(
            startColorstr='#b9f07f',
            endColorstr='#387800',
            GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
}
  </style>
</head>

<body>
<div id="ios-arrow-left"></div>
</body>
</html>



iosBtn.html


#ios-arrow-left 부분이 오른쪽의 큰 사각형 부분입니다.

그 다음 #ios-arrow-left:before 부분이 그 사각형 왼쪽에 작은 사각형을 만든건데요.

rotateZ(45deg) skewY(-0deg) skewX(-0deg); 으로 사각형을 45도 돌립니다.

그리고 Gradient 부분을 보면

        -webkit-linear-gradient(
            -45deg, 
            #b9f07f 0%,
            #8fbd36 9%,
            #387800 94%,
            #74a814 97%,
            #387800 100%); /* Chrome10+,Safari5.1+ */


여기서도 45도 돌려서 gradient 가 그려지도록 만들었습니다.

그러면 45도 돌린 후에는 오른쪽 사각형이랑 제대로 gradient 가 어울리겠죠.


그 다음 #ios-arrow-left:hover 와 #ios-arrow-left:hover:before 부분은 마우스를 올렸을 효과를 구현했습니다.


구현하고 보니까 크롬하고 사파리에서만 돌아가던데요.

(Firefox 와 Opera 같은데서는 작은 사각형의 rotate 가 안되더라구요.)


이번 프로젝트의 target device 는 main 이 blackberry (ver 6,7) 이구요. sub 로 iPad와 iPhone 을 대상으로 합니다.

회사 내부의 특정 business 를 위한 모바일 웹인데 담당자들이 주로 사용하는 디바이스들이 블랙베리랑 iOS 디바이스들이거든요.

이 두 종류의 디바이스에서는 제대로 적용이 됩니다.


그런데 이 효과는 적용하지 않기로 했습니다.

User Experience 부분에서 문제가 있어서 입니다. hover 는 mouseup 이벤트에 해당하는 거고 요즘 사용하는 touch screen 모바일 기기에서는 다른 여러 다양한 이벤트들이 발생하기 때문이거든요.

오른쪽 큰 사각형은 버튼으로 설정이 되서 jQuery Mobile 이 각 이벤트마다 알아서 CSS 처리를 하는데 이 작은 사각형은 그러지 못해서 편안한 UX 를 위해서는 이 touch screen 의 해당 이벤트를 catch 해서 그에 맞는 UI 를 구현해야 하거든요.


이 작은 효과를 내기 위해서 개발에 소요되는 시간이 너무 깁니다.

완전 Time consuming job 이죠.

당연히 jQuery Mobile 에서 지원하지 않는 부분을 매뉴얼로 구현하니까 일일이 이벤트 발생시마다 컨트롤 해야 되는 거겠죠.


처음 이 디자인을 받았을 때 부터 그럴거라고 생각을 했었지만 디자이너와 프로젝트 리더와 프로젝트 매니저를 설득하고 좀 더 효율적이고 유저에게도 도움을 주는 방향으로 프로젝트를 진행해 나갈 수 있게 하려면 충분한 근거를 제시하면서 제 의견을 얘기해야 되겠기에 일단 여기까지 구현하고 직접 디바이스에서 실행하면서 그 장단점을 발표했습니다.


그 결과 이 방법 보다는 버튼 안에 < 이미지를 넣는 방법이 더 효율적이라는 의견을 도출해 냈죠.


그 미팅에 디자이너는 참석하지 않았는데요.

오늘은 추수감사절이라 휴일이고 내일 가서 디자이너에게 자세히 설명하고 버튼안에 들어갈 이미지를 부탁해야 겠습니다.


사실 오늘 그 디자이너 집에 초대받아서 점심 먹고 왔거든요.


여기 추수감사절은 칠면조 요리를 먹는게 전통이지만 그 디자이너가 얼마전에 인도에서 와서 토종 인도 요리로 먹고 왔습니다.



저기 레몬 얹혀 있는 건 수육인데 그건 저희 집에서 준비해 간 거였어요.

마침 그 집안은 목요일에는 고기를 안 먹는다 그래서 한 점도 안 먹었어요. ^^

저 동그란 거는 뿌리라는 요리이고 큰 접시에 담긴건 컬리 플라우어 커리(카레)와 브지인가 브르지인가 하는 계란요리하고 감자요리가 담겨져 있습니다. 그리고 노란 스프같은 건요.

사실 이게 우리나라에서 먹는 커리(카레) 랑 제일 비슷하지만 카레는 아니고 달 이라는 음식입니다.

왼쪽 위에 하얀 접시로 덮여진 것이 밥이구요.


내일은 추수감사절 다음날인 Black Friday 입니다.

저희 회사에서는 휴일은 아니고 대부분 재택근무를 하는데요.

저는 이 디자이너가 미팅이 있어서 회사에 나간다고 해서 같이 나갈려구요.


이 기능을 구현하려고 이것 저것 구글링을 했었는데요.


저 위에 사용한 소스는 아래 싸이트에 있는 소스를 참조한 겁니다.

http://cssnerd.com/2011/11/30/the-best-pure-css3-ios-style-arrow-back-button/


그리고 이미지를 사용해서 구현한 소스도 있는데요.




이 방법은 처음부터 대상에서 제외 했습니다.

기본적으로 이번 프로젝트에서는 버튼을 만들 때 이미지를 사용하지 않거든요.

이 방법을 사용하면 다른 버튼과 조화를 이루는 방법에 아주 많은 공수가 들어갈 겁니다.


아래 정보가 있는 싸이트와 파일을 올립니다.

http://taitems.tumblr.com/post/7240874402/ios-inspired-jquery-mobile-theme-jquery-mobile



iOS-Inspired-jQuery-Mobile-Theme-master.zip



그리고 또 한군데 발견한 곳은

http://appcropolis.com/how-to-make-iphone-back-button-in-jquery-mobile/

입니다.


이 글은 자세히 읽어보지는 못했습니다. 별로일 것 같아서요.

혹시 이 소스 분석해 보시고 저 위에 있는 두가지 방법보다 좋은 것 같으면 알려 주세요.


일단 저 arrow button 효과는 이번 프로젝트에서는 사용하지 않을 거지만 덕분에 좋은 공부를 했고 좋은 자료를 이 블로그에 남길 수 있게 됐습니다.


나중에 진짜 필요한 상황이 오면 큰 도움이 되겠죠.


여러분들도 좋은 하루 보내시고 즐코딩하세요.

저작자 표시 비영리 동일 조건 변경 허락
신고


두개의 select 메뉴가 있는 상황에서 두번째의 select menu 내용이 첫번째 select menu 에 따라 동적으로 종속되는 기능이 있는 샘플 소스를 분석해 보겠습니다.

잘 알아 두면 실무에서 유용하게 사용할 수 있을 것 같네요.

우선 소스 부터 보겠습니다.


<!DOCTYPE html>
<html>
  <head>
    <title>Cascading Selects</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
   
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc1/jquery.mobile-1.0rc1.min.css" />
    <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0rc1/jquery.mobile-1.0rc1.min.js"></script>
    <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
    <script id="childrenTemplate" type="text/x-jquery-tmpl">
      <option value="${k}">${v}</option>
    </script>

    <script>
      var childrenHash = {};
      childrenHash['1'] = [{k: 1, v: "1st child of parent 1"},
                           {k: 2, v: "2nd child of parent 1"}];
      childrenHash['2'] = [{k: 3, v: "1st child of parent 2"},
                           {k: 4, v: "2nd child of parent 2"},
                           {k: 5, v: "3rd child of parent 2"}];
   
      var refreshChildrenSelect = function(parentKey) {
        var children = $('#children');
        children.empty();
       
        $('#childrenTemplate')
          .tmpl(childrenHash[parentKey])
          .appendTo(children);
       
        children.selectmenu('refresh');
      };

      $('#mypage').live('pageinit',function(event) {
        refreshChildrenSelect($('#parent').val());
       
        $('#parent').bind('change', function(event) {
          refreshChildrenSelect($('#parent').val());
        });
      });

    </script>   
  </head>
  <body>
    <div id="mypage" data-role="page">
      <div data-role="header">
        <h1>
          Cascading Selects
        </h1>
      </div>
      <div data-role="content">
        <form>
          <div data-role="fieldcontain">
            <label for="parent">Parent</label>
            <select id="parent" name="parent" data-native-menu="false">
              <option value="1">parent 1</option>
              <option value="2">parent 2</option>
            </select>
          </div>
         
         <div data-role="fieldcontain">
            <label for="children">Children</label>
            <select id="children" name="children" data-native-menu="false">
            </select>
          </div>
        </form>
      </div>
    </div>
  </body>
</html>





이번엔 우선 body 부터 볼까요?

data-role="page" 가 하나 있는 걸로 봐서 이 페이지는 하나짜리 페이지 입니다. 이 파일 내에서의 화면 이동이 없겠네요.

그 다음에 data-role="hearder" 로 페이지 제목을 정해 줬구요.
다음에 data-role="content" 가 왔습니다. 헤더 아래 부분 즉 이 페이지에서 표시될 주요 내용들이죠.


form은 html 태그이구요. 그 다음에 data-role="fieldcontain" 이 선언 됐네요.
실제 예제에서는 이 fieldcontain이 자주 나오는 군요. 시간 내서 숙지해 둬야겠어요.
그 다음에는 첫번째 select form 이 나오는데 제목이 Parent 이고 안의 옵션들은 parent 1, parent 2 이렇게 두가지가 있습니다.

그 다음에 두번째 fieldcontain 이 나오구요. 또 select 메뉴가 나오네요.

이 body 안에는 id 가 첫번째 select 메뉴에 parent로 주어졌고 두번째 select menu에 children으로 주어 졌습니다. 이 두 id 가지고 위의 자바스크립트에서 지지고 볶고 할 거예요.

이제 자바스크립트 쪽을 보겠습니다.

여기서는 $(document).ready(function() {} 같은거 안 썼네요.
뭐 그거 안써도 함수 안에 집어 넣지 않으면 페이지가 로딩될 때 다 실행 될테니까 이 경우에는 상관 없습니다.

childrenHash 라는 배열을 선언했습니다. 지난 글의 myArray 처럼 [] 가 아니라 {} 입니다. 자바스크립트에서는 이중 배열을 쓸 때는 {}를 쓰나요? 둘의 차이를 정확히는 모르겠습니다.
아시는 분 알려 주세요.

이 배열의 첫번째에는 두개의 인자가 들어갔고 두번째 배열에는 세개의 인자들이 들어갔습니다.

그 다음은 refreshChildrenSelect() 라는 함수가 선언됐는데요.

이렇게 함수가 선언되면 자동적으로 실행되는게 아니라 어디에선거 이 함수를 call 해줘야 실행 됩니다.


그 내용을 볼까요?

children 이라는 변수에 아래 두번째 select 메뉴의 아이디인 #children을 넣었습니다.
이 두번째 select에 뭔가를 넣을 건가 봅니다.
그리고 나서 children 변수를 비웠네요. 이 empty() 메소드도 jQuery 메소드이네요.

이건 간단한 거니까 이 글 끝에 예제 복사해 넣어서 나중에 참조해야겠습니다.
아주 간단한 기능이네요.

그 다음은 #childrenTemplate 가 나옵니다. 이것은 지난 번 봤던 jQuery 템플렛입니다.

<option> 태그를 만들어 주는 탬플릿이네요.
childrenHash[] 에 전달받은 매개변수 parentKey를 가지고 아까 childrenHash에서 정해 놨던 1이나 2 를 가져와서 children에 집어 넣는 겁니다.
이 children은 아까 #children을 대입하고 나서 empty() 시켰던 변수죠.
여기에 childrenHash[1] 아니면 childrenHash[2] 가 들어가 있겠네요.

그 다음에 children.selectmenu('refresh'); 로 children select 메뉴를 refresh 했습니다.

여기까지가 parentKey를 받아서 거기에 맞는 childrenHash를 가져와서 body 내에 있는 children select menu에 넣고 refresh 하는 refreshChildrenSelect 함수 내용입니다.


그 다음엔 여러번 봤던 .live 함수가 나오네요.
자세히 분석하지는 않았지만 자주 보니까 웬지 잘 아는 함수 같네요.
여기서는 click event가 아니라 pageinit event 일 경우 이 함수를 실행합니다.
처음에 .ready() 함수를 안 썼는데 여기서는 pageinit 이벤트에서 이 함수를 실행하도록 하면서 처리 했나봅니다.

그렇게 되면 refreshChildrenSelect 메뉴에 현재의 parent value를 매개변수로 전달하면서 call 하게 됩니다. .val() 메소드가 나오네요. 못 보던거니까 일 단 샘플 복사해 넣고 간단하게 분석하고 넘어가겠습니다.


이 소스에서는 이 .val() 부분이 없으면 최초 페이지 로딩할 때 children select menu 에 아무런 value가 없게 됩니다. 그러니까 최초 페이지 로딩이 일어 났을 때 children select menu를 채워주는 일을 하는 곳입니다.

그 다음엔 bind를 사용해서 뭔가 변화가 일어 났을 때 그러니까 parent select menu에 변화가 일어 났을 때 동적으로 child select menu 의 value 값들을 변화시켜 주는 부분 입니다.

처음 보는 메소드들이 몇개 있어서 한번에 해석하지 못하고 약간 멈칫했습니다.

첫번째 것은 .empty() 인데 이건 사실 이름만 보면 알수 있는 거라서 멈칫까지도 안했던 거네요.


<!DOCTYPE html>
<html>
<head>
 
<style>
  p
{ background:yellow; }
</style>
 
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
 
<p>
  Hello,
<span>Person</span> <a href="javascript:;">and person</a>
</p>

<button>Call empty() on above paragraph</button>
<script>
  $
("button").click(function () {
    $
("p").empty();
 
});
</script>

</body>
</html>


예제도 간단해서 이해하기 쉽습니다. 해당 내용을 지워주는 거죠?

두번째 .val() 부분이 좀 멈칫거리게 만들었어요.


<!DOCTYPE html>
<html>
<head>
 
<style>

  p
{ color:blue; margin:8px; }
 
</style>
 
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
 
<input type="text" value="some text"/>
 
<p></p>
<script>
    $
("input").keyup(function () {
     
var value = $(this).val();
      $
("p").text(value);
   
}).keyup();
</script>

</body>
</html>


이건 해당 값을 넣는 거군요.

.html() 이랑 .text() 랑 비슷한거 아닌가 모르겠네요.

.html()은 태그까지 들어가고 .text()는 문자만 들어가는데. .val() 는 select 메뉴의 실제 value 값을 받아오는 것 같습니다.

오늘도 새로운거 몇개 배웠습니다.

have a nice weekend!


저작자 표시 비영리 동일 조건 변경 허락
신고


지난 번 글에서 다룬 몇개의 jQuery API들은 오늘 분석할 샘플 코드에 있길래 미리 공부해 봤습니다.


우선 전체 소스 부터 볼께요.


<!DOCTYPE HTML>
    <html>
    <head>
        <title>checkbox</title>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
        <script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
        <script type="text/javascript">
             var myArray = [];
             $(document).ready(function() {
                // put all your jQuery goodness in here.
                myArray[myArray.length] = 'Item - 0';
                checkboxRefresh();
             });

             function checkboxRefresh(){
                var newhtml = "<fieldset data-role=\"controlgroup\">";
                newhtml +="<legend>Select items:</legend>" ;
                for(var i = 0 ; i < myArray.length; i++){
                    newhtml += "<input type=\"checkbox\" name=\"checkbox-"+i+"a\" id=\"checkbox-"+i+"a\" class=\"custom\" />" ;
                    newhtml += "<label for=\"checkbox-"+i+"a\">"+myArray[i]+"</label>";
                }
                newhtml +="</fieldset>";
                $("#checkboxItems").html(newhtml).page();

                //$('input').checkboxradio('disable');
                //$('input').checkboxradio('enable');
                //$('input').checkboxradio('refresh');
                //$('input:checkbox').checkboxradio('refresh');

                $("input[type='checkbox']").checkboxradio("refresh");

                $('#my-home').page();
             }

            $('#bAdd').live('click', function () {
                myArray[myArray.length] = 'Item - ' + myArray.length;
                checkboxRefresh();
            });
        </script>

    </head>
    <body>
    <div data-role="page" data-theme="b" id="my-home">
        <div id="my-homeheader">
            <h1 id="my-logo">checkbox</h1>
        </div>

        <div data-role="content">

            <div id="checkboxItems" data-role="fieldcontain"></div>

            <fieldset class="ui-grid-b">
                <div data-role="controlgroup" data-type="horizontal">
                    <a id="bAdd" href="#" data-role="button" data-icon="plus" >Add new item</a>
                </div>
            </fieldset>

        </div>
    </div>
    </body>
    </html>


핵심은 bold 처리한 자바스크립트 부분입니다





맨 처음에 myArray라는 배열 변수를 선언 했고 그 다음 $(document).ready(function() {} 이 있습니다.

이건 페이지가 로딩하면 DOM 에 로딩된 직후에 곧바로 실행되는 jQuery 함수입니다.


그 내용을 보니 myArray 에 Item-0 을 대입했네요. 방금전에 빈 myArray[] 배열 변수를 선언했으니까 myArray.length는 0 이겠죠. 그러니까 myArray[0] = 'Item - 0'; 이 실행 됐을 겁니다.


다음에는 checkboxRefresh(); 함수를 call 했네요.

그럼 checkboxRefresh() 함수를 볼까요.


여기에는 newhtml 이라는 변수에 html 코드를 넣었습니다.

fieldset data-role=controlgroup .... 이렇게 계속 넣다가 for 문을 돌리네요.

myArray.length; 만큼 돌리면서 myArray 배열에 있는 값들을 하나 하나 표시하는 for 문입니다.

checkbox를 넣고 그 다음에 배열의 i 번째에 있는 값을 표시하고 그러네요.

마지막엔 </fieldset> 으로 태그를 닫아 주구요.


다음에 $("#checkboxItems").html(newhtml).page(); 가 나옵니다.

밑에 body 안에 보면 id가 checkboxItems 라는 div가 나오죠. 이 안에 newhtml 값을 넣습니다. 지난 글에서 살펴 봤던 .html() 메소드를 사용했습니다. 태그까지 전부 다 넣는 거예요.

그 다음 .page() 가 있는데. 이건 jQuery Mobile 메소드 입니다.

솔직히 뭘 하는지 정확하게 모르겠습니다. 이부분을 빼도 제대로 작동이 되던데...

아마 jQuery Mobile 의 data-role=page 부분에 넣는 것 아닐까요?


사실 $("#checkboxItems").html(newhtml); 여기 까지만 놓고 그 아래 내용은 지워도 원하는 동작은 제대로 합니다.

하여간 그 아래를 보면 .checkboxradio("refresh"); 는  체크박스를 refresh 하는 것 같고 그 아래는 my-home 이란 아이디를 가지고  있는 div  (여기서는 data-role=page) 전체를 page()에 담습니다.


여기까지 하면 myArray 배열에 값이 한개 있기 때문에 1개의 checkboxbutton 만 화면에 나타나겠죠. 이제 버튼을 누르면 라디오 버튼이 하나씩 추가 되는 기능을 보겠습니다.


$('#bAdd').live('click', function () {} 함수가 그 역할을 합니다. .live() jQuery 메소드는 이전 글에서 공부했습니다.

앞에 있는 bAdd 라는 아이디를 갖고 있는 태그 안의 부분을 클릭하면 함수 내에 선언된 동작을 하게 됩니다.


안에를 보면 myArray.length 가 나오죠. 이건 배열의 갯수 이니까. 아까 페이지 오픈할 때 한개가 생겼으니까 1 이 됩니다. 자바계열에서는 배열의 시작을 0부터 시작하니까 myArray[1] 이 되면 두번째가 됩니다.

그러니까 bAdd를 클릭 할 때마다 배열이 한개씩 늘어 나게 되겠죠.


그리고 나서 checkboxRefresh() 를 부르게 되면 배열 갯수 만큼 checkboxbutton을 화면에 뿌려주는 로직이니까 하나씩 늘어나게 될 겁니다.


여기까지가 동적인 효과를 주는 자바스크립트 부분입니다.

대부분 jQuery 메소드를 사용했습니다.

그 아래 body 부분은 html 입니다.

jQuery Mobile 에 대해서 알아야겠죠? 이 코드를 이해하려면요.

처음에 data-role로 페이지를 설정했고 style은 b  로 적용했고 이 페이지의 id는 my-home 입니다.

이 아이디는 checkboxRefresh() 함수에서 맨 마지막에 .page() 메소드를 사용할 때 이용됩니다.

그리고 아래 내용 중에 봐야될 부분은 data-role="content" 부분이 있고 (이것도 jQuery Mobile의 중요한 개념입니다.) 그 안에 data-role="fieldcontain" 이 있습니다.


jQuery Mobile이 생소하신 분들은 이 data-role에 대해 알아야 겠다는 느낌이 팍팍 드시죠?

따로 찾아 보시기 바랍니다.

제 블로그에도 정리가 돼 있습니다.


위에 자바스크립트를 보시면 새로 추가되는 체크박스 버튼이 fieldcontain (id="checkboxItems") 안에 추가 되고 있습니다.

id는 이렇게 자바스크립트에서 catch해서 어떤 작업을 할 때 요긴하게 쓰입니다.


그 다음은 data-role="controlgroup" 이 있죠. 아마 button을 그룹화 할 때 사용하는 data-role 일 겁니다.

그리고 그 안에는 버튼을 한개 만들었습니다. 여기서 id="bAdd" 를 갖고 위에 자바스크립트에서 catch 해가지고 어떤 작업을 했습니다.


분석하면서 보니까 별로 막히는 부분은 없었네요.

모르는 부분을 미리 보고 해석하니까 잘 진행 됐던것 같습니다.


여기서 더 이 소스를 내것으로 만드려면 이것 저것 수정해 보면서 확실하게 익히는 겁니다.

이게 제가 공부하는 방법입니다.

수정해 보시고 다른 앱에 응용해 보시면 더 좋겠죠.


그럼....

저작자 표시 비영리 동일 조건 변경 허락
신고


제가 받은 이 To-Do List 소스코드가 있는 곳을 찾았습니다.

여기로 가시면 보실 수 있으세요.


제가 이전 글에서 소스코드를 올렸나요?

만약 올렸다면 그건 잘 못 된 소스코드일 겁니다. 제가 잘 못 알았었나봐요.

위 링크를 따라 가시면 설명과 함께 소스코드를 받아 보실 수 있습니다.


그럼 to-do.js를 계속 분석 해 볼까요?


var model = new Model(),  listHeaders = [];

여기까지 했죠?


이건 뭔 뜻인지 제가 좀 헛갈립니다. 자바스크립트 문법을 잘 몰라서.

아마 Model() 의 객체를 model 변수에 담는데 이게 그 안에 배열이 있으니까 listHeaders 에 그 내부의 배열을 담나 봅니다.

좀 이상하긴 한데 머 아님 말구요.

다음 소스 분석하다 보면 답이 나오겠죠 뭐.


그 다음은 getListHeaders() 함수인데요.

$().each 메소드가 나왔습니다. jQuery 메소드죠.

이 메소드의 API는 위에 링크 걸어 놨는데요. 자세히 설명 돼 있습니다.


    (function getListHeaders() {
        $("#todoList > li[data-priority]").each(function() {
            listHeaders[parseInt($(this).attr("data-priority"))] = $(this);
        });
    })();
이 의미는 id가 todoList인 곳의 li 에서 data-priority 별로 정보를 받아서 listHeader에 그 값을 넣는 겁니다.

그러면 priority 별로 데이터들이 모이겠네요.


그 다음은 템플릿 플러그인을 사용하는 함수가 나옵니다.


    var renderItemElement = function(item) {
        return $.tmpl("<li data-icon=\"delete\" class=\"item\"><a>${text}</a></li>", item)
            .data("item", item)
            .insertAfter(listHeaders[item.priority]);
    };


이 의미는 listHeader 다음에 data-icon 을 delete로 하고 class를 item으로 하는 그리고 ${text} 가 브라우저에 표시되는 그런 패턴을 삽입하라는 겁니다.

첫번째 화면에 입력한 값이 들어가면 각 priority 아래에 그 내용들이 들어가는데 그 내용들에 대한 탬플릿을 추가하는 겁니다.




Sample Item #1 이 ${text} 이고 그 오른쪽에 data-icon = delete 가 되서 X 표시가 있죠? 이 라인을 만드는 함수 입니다.


다음은 id 가 createButton 인것이 클릭 되면 어떤 동작을 하는 함수인데요.


    $("#createButton").click(function() {
        var priority = parseInt($("#todoUrgency").val()),
            item = model.create($("#todoDescription").val(), priority);

        renderItemElement(item);

        $("#todoList").listview("refresh");
        $("#todoUrgency").val(model.PRIORITY.NORMAL.toString()).trigger("change");
        $("#todoDescription").val("");       
    });


두 번째 화면의 Create 버튼이 클릭 되면 todoUrgency 가 id 인 곳의 값을 받아서 숫자로 형변환을 한 다음에 이것을 priority 변수에 넣습니다. 그리고 id가 todoDescription인 곳의 값을 받아서 그 priority와 함께 var Model = function() {} 함수 안에 있는 this.create 함수를 실행하는 겁니다. 

model.create()를 불러왔죠?

여기서는 인수로 받은 text,priority 값을 key, value 형태로 result에 담고 이것을 items에 push 합니다.

그리고 나서 save() 함수를 불러오는데 이 부분에서 쿠키를 만들어 주는 겁니다.


그러니까 두번째 화면에서 클릭하면 그 값들을 parsing 하고 변수에 담아서 items에 push 하고 이것을 쿠키로 만들어 지는 것 까지 자동적으로 이뤄지네요.

쿠키를 만든 다음엔 renderItemElement에 방금 만든 item을 보내서 X 표시가 있어서 데이터를 delete 할 수 있는 탬플릿을 만들구요. 

jQuery의 .listview() 메소드를 이용해서 #todoList 리스트 뷰를 refresh 합니다.


그리고 나서 두번째 페이지의  form 의 각 값들을 초기화 시키는 군요.


다음 함수의 .delegate() 도 jQuery 함수인데요. 

첫번째 인수를 클릭했을 때 어떤 일을 하라고 할 때 사용되는 겁니다.


    $("#todoList").delegate("li.item", "click", function() {
        model.remove($(this).data("item"));
        $(this).slideUp(function() {
            $(this).remove();
        });
    });


즉 #todyList의 li.item 을 클릭하면 model의 remove를 실행하는 군요.

그럼 해당 아이템은 없어지고 그 아래 아이템들은 slideUp 되도록 하는 겁니다.


마지막 함수는

    (function renderExistingItems() {
        $(model.getItems()).each(function() {
            renderItemElement(this);
        });

        $("#todoList").listview("refresh");
    })();

입니다.


model에 있는 getItems를 호출해서 .each() 메소드 처리를 하는 군요.

아까 처럼 각각 탬플릿 화 하는 겁니다. x표가 들어간 item을 만드는 거죠.

그리고 #todoList 리스트 뷰를 refresh 합니다.


지금까지 소스를 따라가면서 해석 해 봤는데요.


생각보다 쉬운건 아니네요.


자바스크립트나 jQuery 메소드들에 대해서 계속 공부하고 실습하고 해야 익숙해 질 것 같습니다.


jQuery Mobile 만 봤을 때는 아주 쉬워 보였는데 이걸 가지고 어떤 앱을 만들려니까 여러가지 배울것들이 더 많군요.


당분간 계속 샘플 앱 소스를 분석해야겠어요.

저작자 표시 비영리 동일 조건 변경 허락
신고


이제 제가 구한 To-Do List 의 자바스크립트 부분을 공부해 보겠습니다.

저도 자바스크립트는 그냥 소스 긁어다가 사용하는 수준이라서 잘 모르거든요. 그래서 이렇게 jQuery Mobile 제대로 들어가기 전에 자바스크립트 사용법 부터 공부하려고 소스 분석 하는 거 같아요.

지난번 글에서는 jQuery Mobile로 만든 두페이지 짜리 화면을 만드는 소스를 분석해 봤는데요.

오늘 배울 자바스크립트 부분을 작동 시키려면 지난번 그 index.html 파일의 header 안에 4개의 자바스크립트 링크를 더 달아야 합니다.


    <script src="./json2.js"></script>
    <script src="./jquery.cookie.js"></script>
    <script src="./jquery.tmpl.js"></script>
    <script src="./to-do.js"></script>


위에 3개는 이 예제소스 공부하기 전에 각각 대략의 사용법을 정리했었습니다.



지금 공부해야 할 부분은 to-do.js 입니다.

전체 소스는 아래와 같습니다.


$(document).ready(function() {

    var Model = function() {

        var items = [],
            load = function() {
                items = JSON.parse($.cookie("model") || "[]");
            };

        this.PRIORITY = {
            IMPORTANT: 2,
            NORMAL: 1,
            LOW: 0
        };

        this.save = function() {
            $.cookie("model", JSON.stringify(items), { expires: 365 });
        };

        this.create = function(text, priority) {
            var result = { "text": text, "priority": priority };

            items.push(result);
            this.save();

            return result;
        };

        this.remove = function(item) {
            items.splice($(items).index(item), 1);
            this.save();
        };

        this.clear = function() {
            items = [];
            this.save();
        };

        this.getItems = function() {
            var result = [];

            for (var index = 0, max = items.length; index != max; index++) {
                result.push(items[index])
            }

            return result;
        };

        load();
    };

    var model = new Model(),
        listHeaders = [];

    (function getListHeaders() {
        $("#todoList > li[data-priority]").each(function() {
            listHeaders[parseInt($(this).attr("data-priority"))] = $(this);
        });
    })();

    var renderItemElement = function(item) {
        return $.tmpl("<li data-icon=\"delete\" class=\"item\"><a>${text}</a></li>", item)
            .data("item", item)
            .insertAfter(listHeaders[item.priority]);
    };

    $("#createButton").click(function() {
        var priority = parseI  nt($("#todoUrgency").val()),
            item = model.create($("#todoDescription").val(), priority);

        renderItemElement(item);

        $("#todoList").listview("refresh");
        $("#todoUrgency").val(model.PRIORITY.NORMAL.toString()).trigger("change");
        $("#todoDescription").val("");       
    });

    $("#todoList").delegate("li.item", "click", function() {
        model.remove($(this).data("item"));
        $(this).slideUp(function() {
            $(this).remove();
        });
    });

    (function renderExistingItems() {
        $(model.getItems()).each(function() {
            renderItemElement(this);
        });

        $("#todoList").listview("refresh");
    })();   
});


처음에 $(document).ready(function() {}); 부분이 나오는데요.
이건 jQuery의 메소드 입니다.
자바스크립트의 window.onload 와 비슷한건데요. window.onload 가 전체 페이지가 다 로드 된 다음에 시작하는 거라면 $(document).ready(function() {}); 는 DOM 이 다 읽혀지기만 하면 곧바로 시작합니다.

그리고 한 파일에서 여러분 사용해도 jQuery 가 알아서 처리해 주구요. window.onload는 그러면 에러가 났거든요.

이렇게 to-do.js는  jQuery 메소드로 페이지가 로드되면 자동으로 실행 되도록 만들었네요.

그 다음에는 함수가 하나 있는데요. var Model = function() {}

Model 이라는 변수명을 가진 함수 입니다.
이 함수 안에는 처음에 var items 변수가 나오는데 이건 배열이네요.
json2.js 파일에 있는 JSON.parse() 메소드를 사용해서 쿠키의 내용을 배열 변수에 담는가 봅니다.
그 다음은 PRIORITY 선언이 있고 다음은 쿠키를 만드는 건데 expire 기간을 1년으로 잡았습니다.

여기서 $.cookie 로 시작하는 것은 아시겠지만 jquery.cookie.js 플러그인에 있는 메소드를 사용할 때 필요한 겁니다.

그 다음 함수인  this.create = function(text, priority) 는 뭘까요?

일단 text와 priority를 받는거네요. 그리고 이 받은 값들을 this.save(); 를 call 해서 쿠키로 저장하는 군요. 그 다음에 결과값을 return 하구요.

this.remove = function(item) 는 쿠키를 remove 하는 것 같습니다.

this.clear = function() 는 items 배열을 싹 비우는 함수구요.

this.getItems = function() 는 items의 갯수를 구해서 전부를 push 하는군요.

load(); 는 jQuery 의 메소드로서 HTML을 로드하고 DOM 에 삽입하는 겁니다. Ajax 기능이죠.

var Model = function() {}은 MVC 패턴 중에 M(Model) 부분을 구현한 거군요.
Model은 주로 비지니스 로직을 구현하는 거죠. 이 앱의 경우에는 여러 아이템들을 추가 삭제하고 쿠키를 만들거나 삭제하는 것 같은 비지니스 로직들이 이 안에 들어가 있습니다.

var model = new Model(),        listHeaders = [];

이거는 뭘까요? 지금까지 만든 Model에 대한 객체를 만들고 그 변수 이름을 model이라고 하구요. 그런데 listHeaders=[];는 왜 붙었을 까요.

오늘은 다른 할 일이 있어서 여기까지 해야 겠네요.

제가 자바스크립트는 잘 몰라서 그냥 제가 이해하는 만큼만 정리한 건데요.

제가 느끼기에 제가 좀 부족하게 이해한 것 같은데요.

자바스크립트 잘 아시는 분 있으시면 조언 좀 해 주세요.

시간 있을 때 차근차근 하나 하나 찾아가면서 마저 공부해야 겠습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고


지난 시간에 얘기했던 것 처럼 오늘부터는 소스를 분석해 보겠습니다.


우선 index.html부터 보겠습니다.

일반 웹페이지 만들 때와 똑 같겠죠? jQuery Mobile로 화면부터 만들고 난 다음에 javascript로 dynamic 한 효과를 줍니다.


그럼 jQuery Mobile을 사용하기 위해서는 관련된 js 파일과 css 파일을 불러와야 겠죠.


그리고 이 앱은 두개의 페이지로 돼 있으니까 data-role="page" 가 들어가 있는 div 를 두개 만들어야 할 겁니다.


나머지는 화면에 보이는대로 각 위젯들을 갖다가 넣으면 됩니다.


그럼 전체 소스를 한번 보죠.


<!DOCTYPE html>
<html>
    <head>
    <title>Mobile To-Do</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
    <script src="http://code.jquery.com/jquery-1.5.2.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>  
</head>
<body>
<div id="mainPage" data-role="page">
    <div data-role="header">
        <h1>Mobile To-Do List</h1>
        <a href="#addPage" data-role="button" data-icon="plus">New</a>
    </div>
    <div data-role="content">
        <ul id="todoList" data-role="listview">
            <li data-priority="2" data-role="list-divider">Important</li>
            <li data-priority="1" data-role="list-divider">Normal</li>
            <li data-priority="0" data-role="list-divider">Low</li>
        </ul>       
    </div>
</div>
<div id="addPage" data-role="page">
    <div data-role="header">
        <a href="#mainPage" data-role="button" data-icon="back">Back</a>
        <h1>New To-Do</h1>
        <a href="#mainPage" id="createButton" data-role="button" data-icon="plus">Create</a>
    </div>
    <div data-role="content">
        <div data-role="fieldcontain">
            <label for="todoDescription">Description:</label>
            <input type="text" name="todoDescription" id="todoDescription" value=""  />
        </div>
        <div data-role="fieldcontain">
            <label for="todoUrgency" class="select">Urgency:</label>
            <select name="todoUrgency" id="todoUrgency" data-native-menu="false">
                <option value="2">Important</option>
                <option value="1" selected="selected">Normal</option>
                <option value="0">Low</option>
            </select>
        </div>       
    </div>
</div>
</body>
</html>


첫번째 줄의 <!DOCTYPE html> 는 HTML5를 사용한다는 태그이구요.

그 다음부터 본격적인 html 이 시작됩니다.

먼저 head 부분이 오게 되는데 이곳에는 title이 있고 필요한 자바스크립트나 스타일 쉬트 파일을 참조하는 태그들이 있습니다.

여기서는 jQuery Mobile을 사용하기 위해 필요한 두개의 자바스크립트 파일과 한개의 스타일 쉬트 파일을 참조했습니다.

오늘은 화면 구성만 할 거기 때문에 다른 dynamic한 처리를 하기 위한 자바스크립트는 일단 제외했습니다.

그건 다음글에서 다룰 생각입니다.


그 다음 나오는 <body> 서부터가 실제로 브라우저에 표시될 내용들입니다.

우선 data-role="page" 가 있는 div를 두개 만들어서 jQuery Mobile에서 사용할 두개의 페이지를 나눕니다. 하나는 mainPage 이고 또 다른 하나는 addPage 이네요.


우선 mainPage 부터 볼까요.


이 mainPage에는 header와 contents 가 있습니다. 이 둘을 나누는 것은 data-role= 를 이용해서 나누구요. 물론 div안에 그것을 넣습니다.

header 부분에는 제목과 New 버튼이 들어가네요.

jQuery Mobile의 header에서는 링크를 만들면 자동적으로 버튼으로 처리하죠?

그리고 그 버튼은 좌,우 각 한개씩 두개까지 만들 수 있습니다.


여기서는 이 New 버튼을 누르면 뭔가가 실행이 되겠네요.#addPage로 링크가 걸렸으니까 그 페이지가 뜰 겁니다.

그럼 addPage는 새로운 것을 입력하는 form 이겠네요.

그건 나중에 보기로 하고.....

그 다음 content 부분에서는 세개의 item 이 있는 listview를 만들었습니다.

data-role 이 listview로 돼 있죠? 그 다음에 아이템들에는 data-role이 list-divider로 돼 있고 각각 data-priority 가 등록 돼 있습니다.

이제 첫번째 페이지가 완성 됐네요.


여기까지 하면 위 화면을 볼 수 있습니다.

다음 두번째 페이지인 addPage를 볼까요.

여기도 mainPage와 마찬가지로 header와 contents 두개가 가장 윗단에 있습니다.

헤더 안에는 #mainPage로 가는 링크가 두개가 있네요. 이 링크는 data-role이 button 입니다.

두개가 다른 것은 두번째 버튼(Create)에는 id="createButton" 이 있습니다

(data-icon 도 다르네요.)

두번째 버튼에 id 를 준 것은 이 아이디를 가진 버튼이 클릭 됐을 때 자바스크립트에서 어떤 동작을 하도록 하기 위해서 입니다.

이 자바스크립트 부분은 다음 글에서 분석해 보겠습니다.

두번째로 content 부분을 볼까요.

여기엔 data-role="fieldcontain" 부분이 두개가 있습니다.

첫번째 것에는 Label 하고 input 박스가 있습니다.

두번째 input 박스에는 id="todoDescription" 이 있죠? 이렇게 id 가 있는 태그는 대부분 자바스크립트에서 어떤 처리를 하는데 필요한 것들이라고 보시면 됩니다.

두번째 fieldcontain에는 Label 하고 select 메뉴가 있습니다. 디폴트로 Normal 이 select 되도록 되 있네요.


두번째 화면을 브라우저에서 실행시키면 위와 같이 됩니다.


첫번째 화면에서 New를 클릭하면 두번째 화면이 나오고 두번째 화면에서 Back을 하거나 Create 버튼을 누르면 다시 첫번째 화면이 나오죠.

아직 자바스크립트 부분을 완료하지가 않아서 form에 value를 넣고 Create를 눌러도 첫번째 화면에는 아무런 변화가 없을 겁니다.

그 자바스크립트 부분은 다음 글에서 다룰 께요.

저작자 표시 비영리 동일 조건 변경 허락
신고


jQuery Mobile을 배우는데 Tutorial을 봐도 깔끔하게 정리되지 않아서요.

뭔가 제대로 된 App 소스 하나.. 완성된 App 소스 하나 제대로 분석해 보면 좀 더 많이 이해 되지 않을까 싶은 마음에 ....


여기 저기 소스코드를 찾다가 Mobile To-Do List를 찾았습니다.


지난 세기(Century)에 처음 웹 프로그래밍을 배울때 쇼핑몰 소스 가지고 설명한 책을 사서 무조건 개발에 들어갔던 기억이 나네요.


PHP로 만든건데.. 그때는 PHP 뿐만이 아니라 아무런 언어도 배우지 않았을 때거든요.


대충 한두달 짜리 강좌는 들었지만 전혀 프로그래밍과는 상관없는 문과 출신이어서 뭔소린지 도통 이해 못하겠더라구요.

그래서 이해하고 뭘 시작하면 안될것 같아서.. 무작정 쇼핑몰 개발에 들어갔죠..


jQuery Mobile도 튜토리얼을 통해 각 기능만 봤을 때는 쉬워보이더만 막상 뭘 개발하려고 하니까 이것 저것 막히는게 많네요.


튜토리얼을 어느정도 공부했으니 이제부터는 여기 저기 샘플 소스 코드 사냥에 나서서 분석하고 응용해서 내것도 만들고 그래야 겠어요.


제가 찾은 소스는 Mobile To-Do List 입니다.

여기로 가시면 소스코드를 다운 받을 수 있습니다.


뭐 혼자 소스 분석 하실 수 있으신 분은 직접 다운받아서 하시면 됩니다.

이 블로그는 제가 공부하기 위해서 만든거니까 저는 그냥 제 공부를 위해서 정리해 놓는것 뿐입니다.


혹시 다른 분들 좋은 jQuery Mobile로 만든 좋은 샘플 앱 소스코드 있으시면 정보 부탁드려요.

제가 잘 분석해서 여기에 올릴께요.


먼저 제가 분석할 Mobile To-Do List 앱 화면은 아래와 같습니다.



index.html을 치시면 위와 같은 화면이 나올겁니다.

처음 실행 시키는 거니까 내용은 아무것도 없습니다.

내용을 만들려면 New 버튼을 클릭합니다.




그러면 내용을 넣을 수 있는 화면이 나옵니다.

우선 Description을 넣고 select 메뉴에서 중요도를 정합니다.

제대로 작성했으면 Create 버튼을 누릅니다.



그러면 다시 첫번째 화면으로 오는데요.

좀 전에 저장한 데이터가 쿠키로 저장되고 그것을 불러와서 화면에 뿌려 줍니다.

오른쪽에 있는 X 버튼을 누르시면 해당 내용이 지워지구요.


보니까 딱 2페이지 짜리 앱이네요.


우선 jQuery Mobile로 두 페이지를 만들고 버튼들에 각각 이벤트가 일어나면 어떤 일을 하도록 JavaScript로 프로그래밍을 해야 할 것 같습니다.


그럼 다음 글 부터 직접 소스코드를 놓고 분석을 해 봐야겠습니다.


참 이 소스코드를 분석하려고 바로 전에 jquery.cookie.js, jQuery.tmpl, json2.js  플러그인을 분석했습니다.


필요하신 분들은 그 글들 먼저 보시면 좋을 거예요.


저작자 표시 비영리 동일 조건 변경 허락
신고

json2.js 플러그 인 알아보기

2012.08.04 20:38 | Posted by 솔웅


Parsing a message in JavaScript with JSON


지난 시간에 자바스크립트에서 JSON을 어떻게 생성하는지에 대해 배웠습니다. 이제 자바스크립트에서 JSON 안의 메세지를 어떻게 parse 하는지에 대해 알아보겠습니다.

"String.parseJSON(filter)" 메소드를 이용해서 자바스크립트 내에서 JSON으로 메세지를 parse 할 수 있습니다. 이 JSON 메세지는 sting이나 객체로 parse 됩니다. filter 파라미터는 optional 입니다. filter 메세지나 결과를 transform 하는데 사용됩니다. 이 메소드는 자바스크립트의 eval()메소드를 message parse를 위해 내부적으로 사용합니다.

아래 ParseMessageJSON.htm의 전체 예제 코드가 있습니다.



ParseMessageJSON.htm


<html>
<head>
<title>Parsing Message using JSON in JavaScript</title>
<script language="javascript" src="json2.js"></script>
<script language="javascript" >
var students = {
   
"Maths" 
  "Name"  "Amit",  // First element
  "Marks" 67,
  "age" 23 },  
  {
   "Name"   "Sandeep",  // Second element
  "Marks" 65,
  "age" 21 }
 
 
// Printing Maths array values in the alert message
var i=0
var arrayObject = new Array();
for(i=0;i<students.Maths.length;i++)
{  
  arrayObject.push(students.Maths[i].Name);
  arrayObject.push(students.Maths[i].Marks);
  arrayObject.push(students.Maths[i].age);
}  
  alert("Parsing JSON Message Example ");
  alert(arrayObject.toJSONString().parseJSON());
</script>
</head>
<body>
 Parsing Message using JSON in JavaScript
</body>
</html>



이 예제를 실행시키려면 json2.js 파일이 필요합니다. 이 파일을 ParseMessageJSON.htm내에 include 해야 합니다. 이 json2.js는 creating message in JavaScript with JSON 강좌에서 사용했던 것과 같은 겁니다.


Output:


ParseMessageJSON.htm를 실행시키시면 아래와 같은 결과가 나올 겁니다.




Download Code


======== o ========= o ============ o ============= o =============


지금까지 3개의 article 을 통해서 쿠키, 탬플릿, json 관련된 플러그인 사용법을 알아봤습니다.

jQuery Mobile 샘플을 하나 분석해 보려고 봤더니 이 3개의 플러그인이 있어서 공부해 봤습니다.

아주 도움이 많이 된 것 같네요.


마지막 플러그인인 json2.js 는 이 글가지고 약간 부족할 수도 있을 것 같은데요.

네이버에서 json2.js로 검색하셔서 따로 읽어 보세요.


그럼 다음시간에는 원래 하기로 했던 jQuery Mobile 예제 파일을 분석해 보겠습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고


jQuery.tmpl( template [, data] [, options] ) Returns: jQuery


Description: Render the specified HTML content as a template, using the specified data.


  • jQuery.tmpl( template [, data] [, options] )    

  • version added: 1.4.3

    template The HTML markup or text to use as a template.

    data The data to render. This can be any JavaScript type, including Array or Object.

    options An optional map of user-defined key-value pairs. Extends the tmplItem data structure, available to the template during rendering.


이 글은 jQuery Templates 플러그인 (jquery-tmpl)과 관련된 문서입니다. 이 플러그인은  http://github.com/jquery/jquery-tmpl 에서 다운로드 받으실 수 있습니다.

jQuery.tmpl() 메소드는 .appendTo, .prependTo, .insertAfter, .insertBefore 같은 것들과 어울려 아래의 예제처럼 사용되도록 만들어 졌습니다.


Example:


$.tmpl( "<li>${Name}</li>", { "Name" : "John Doe" }).appendTo( "#target" );




이 template 파라미터는 다음과 같은 것들이 될 수 있습니다.

  • 마크업을 포함한 string
  • 템플렛으로 사용되기 위한 콘텐트를 가지고 있는 HTML element (혹은 element로 둘러 싸여져 있는 jQuery 객체)
  • named template의 이름과 연관돼 있는 string (jQuery.template() and .template() 를 보세요.)
  • 컴퍼일된 템플렛 함수 ( jQuery.template() and .template() 를 보세요.)


만약에 data가 배열이라면 그 탬플릿은 배열의 각 아이템에 대해 한번 render 됩니다. 데이터가 객체이거나 data 파라미터가 없거나 null 이라면 single template item이 render 됩니다.

return 값은 렌더링된 탬플릿 아이템으로 만들어진 element들의 jQuery collection 입니다. (각 배열에 있는 하나 혹은 각각의 데이터 아이템). 만약 템플렛에 top level element만이 포함돼 있다면 배열의 각 데이터에 대해 한개의 element가 있게 됩니다.


HTML DOM에 렌더링된 템플릿 아이템을 insert 하기 위해 리턴된 jQuery collection은 DOM에 directly insert 되면 안됩니다. .appendTo, .prependTo, .insertAfter or .insertBefore 등과 연결되서 사용되어져야 합니다.


$.tmpl( myTemplate, myData ).appendTo( "#target" );


See also .tmpl().


Example


아래 예제는 jQuery.tmpl()을 로컬데이터로 render 하기 위해 어떻게 사용되는지를 보여 줍니다. template은 하나의 string 이 사용됐습니다.


<ul id="movieList"></ul>

<script type="text/javascript">
  var movies = [
      { Name: "The Red Violin", ReleaseYear: "1998" },
      { Name: "Eyes Wide Shut", ReleaseYear: "1999" },
      { Name: "The Inheritance", ReleaseYear: "1976" }
  ];

  var markup = "<li><b>${Name}</b> (${ReleaseYear})</li>";

  // Compile the markup as a named template
  $.template( "movieTemplate", markup );

  // Render the template with the movies data and insert
  // the rendered HTML under the "movieList" element
  $.tmpl( "movieTemplate", movies )
      .appendTo( "#movieList" );
</script>


Using Remote Data


일반적으로 데이터는 로컬이 아닙니다. 대신에 데이터는 리모트 서비스나 페이지로 request 하는 Ajax를 사용합니다. 아래 그 예제가 있습니다.



var markup = "<li><b>${Name}</b> (${ReleaseYear})</li>";

// Compile the markup as a named template
$.template( "movieTemplate", markup );

$.ajax({
  dataType: "jsonp",
  url: moviesServiceUrl,
  jsonp: "$callback",
  success: showMovies
});

// Within the callback, use .tmpl() to render the data.
function showMovies( data ) {
  // Render the template with the "movies" data and insert
  // the rendered HTML under the 'movieList' element
  $.tmpl( "movieTemplate", data )
    .appendTo( "#movieList" );
}


The Markup for the Template


여러분은 (computed 되거나 원격으로 obtained 되었을) string 으로부터 혹은 페이지에 있는 inline markup으로부터 템플릿을 위한 markup을 받을 수 있습니다. 어떻게 inline markup을 사용하는지를 보시려면 .tmpl()를 보세요.


Caching the Template


탬플릿이 렌더링 될 때 markup은 우선 컴파일된 탬플릿 function으로 convert 됩니다. 항상 $.tmpl( markup , myData ).appendTo( "#target" )이 call 됩니다. 이 탬플릿은 recompile 됩니다. 만약 같은 탬플릿이 렌더링 데이터로 한번 이상 사용된다면 이 compil된 템플릿이 cache 될 거라는 걸 염두에 두세요. 페이지의 inline markup 에서가 아니라 string 으로ㅜ터 획득 된 markup을 사용할 때 템플릿을 cache 하기 위해서는 재사용을 위해 named template을 생성하기 위해 $.template( name, markup )를 사용하세요.


Template Tags, Expressions, and Template Variables


${}같은 탬플릿 태그들은 text와 HTML markup을 추가할 수 있도록 jQuery 탬플릿 안에서 사용될 수 있습니다. 이러면 탬플릿의 composition, hierarchical data에 대한 iteration, 탬플릿 렌더링의 parameterization 같은 여러 상황에서 유용하게 사용될 수 있겠죠. 탬플릿 태그들은 데이터 아이템 필드의 value들에 기초한 content나 $item 같은 탬플릿 변수를 렌더링할 수 있습니다. 각각의 탬플릿 태그들에 대해 알아보시려면 다음 문서들을 보세요. ${}, {{each}}, {{if}}, {{else}}, {{html}}, {{tmpl}} and {{wrap}}


The options Parameter, and Template Items


탬플릿내의 데이터 아이템이 렌더링 된 결과인  각 탬플릿 아이템들은 tmplItem data structure 와 연관되어 있습니다. 이것은 jQuery.tmplItem().tmplItem(), 혹은 $item template 변수를 사용해서 접근될 수 있습니다. jQuery.tmpl()의 옵션 파라미터로 pass 된 필드들이나 anonomyous methods 들은 tmplItem data structure를 extend 할 겁니다. 그리고 다음의 예제에서 처럼 탬플릿화 할 수 있습니다.


var markup = "<li>Some content: ${$item.myMethod()}.<br/>" 
           + " More content: ${$item.myValue}.</li>";

// Compile the markup as a named template
$.template( "movieTemplate", markup );

// Render the template with the movies data
$.tmpl( "movieTemplate", movies,
  { 
      myValue: "somevalue", 
      myMethod: function() { 
          return "something";
      } 
  } 
).appendTo( "#movieList" );


Additional Notes:


  • Netflix recently changed the API that we use in the remote service example below. We are aware that this change breaks the demo and will work on an update as soon as we can.


Examples:


Example: Render local data using jQuery.tmpl().


<!DOCTYPE html>
<html>
<head>
 
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
 
<script src="http://ajax.microsoft.com/ajax/jquery.templates/
beta1/jquery.tmpl.min.js"
></script>
</head>
<body>
 
<ul id="movieList"></ul>

<script>
 
var movies = [
 
{ Name: "The Red Violin", ReleaseYear: "1998" },
 
{ Name: "Eyes Wide Shut", ReleaseYear: "1999" },
 
{ Name: "The Inheritance", ReleaseYear: "1976" }
 
];

var markup = "<li><b>${Name}</b> (${ReleaseYear})</li>";

/* Compile the markup as a named template */
$
.template( "movieTemplate", markup );

/* Render the template with the movies data and insert
   the rendered HTML under the "movieList" element */

$
.tmpl( "movieTemplate", movies )
 
.appendTo( "#movieList" );
</script>

</body>
</html>

Demo:

Example: Render data from a remote service, using jQuery.tmpl().

<!DOCTYPE html>
<html>
<head>
 
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
 
<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/
jquery.tmpl.min.js"
></script>
</head>
<body>
 
<button id="cartoonsBtn">Cartoons</button>
<button id="dramaBtn">Drama</button>

<ul id="movieList"></ul>

<script>
var markup = "<li><b>${Name}</b> (${ReleaseYear})</li>";

/* Compile the markup as a named template */
$
.template( "movieTemplate", markup );

function getMovies( genre, skip, top ) {
  $
.ajax({
    dataType
: "jsonp",
    url
: "http://odata.netflix.com/Catalog/Genres('" + genre
   
+ "')/Titles?$format=json&$skip="
   
+ skip + "&$top=" + top,
    jsonp
: "$callback",
    success
: function( data ) {
     
/* Get the movies array from the data */
     
var movies = data.d;

     
/* Remove current set of movie template items */
      $
( "#movieList" ).empty();

     
/* Render the template items for each movie
      and insert the template items into the "movieList" */

      $
.tmpl( "movieTemplate", movies )
     
.appendTo( "#movieList" );
   
}
 
});
}

$
( "#cartoonsBtn" ).click( function() {
  getMovies
( "Cartoons", 0, 6 );
});

$
( "#dramaBtn" ).click( function() {
  getMovies
( "Drama", 0, 6 );
});

</script>

</body>
</html>



저작자 표시 비영리 동일 조건 변경 허락
신고


Working with cookies using jQuery and JavaScript


jQuery나 Javascript를 통해 쿠키를 사용하는 overview 입니다.

오늘은 jQuery 나 pure javascript 를 통해서 쿠키를 쉽게 사용할 수 있도록 하는 몇가지 테크닉을 다루겠습니다.


What is a cookie?


쿠키는 Hypertext Transfer Protocol (HTTP) requests 와 response 를 포함하고 있는 text string 입니다. 쿠키는 state 정보를 유지하기 위해 사용됩니다. 여러 웹사이트를 돌아다니다가 그 웹사이트에 다시 돌아왔을 때 일관성을 유지시켜주기 위해 사용되는 것이죠. 이 글은 쿠키에 대한 정보를 제공하고 있습니다.


What do i do with cookies


요즘은 주로 쿠키가 유저의 로그인 정보를 저장하기 위해서 가장 많이 쓰이고 있습니다. 이 의미는 유저가 로그인 된 상태로 특정 시간동안 유지하도록 하는 기능을 쿠키가 제공해 주고 있다는 것이죠. 그 이외에도 그 웹사이트에 머물러 있었던 마지막 순간의 정보에 대한 아주 temporary 한 정보들을 저장하기도 합니다.


쿠키는 외부로부터 여러분의 웹사이트에 의해 혹은 유저에 의해 접근해야될 필요가 있는 정보 저장에는 사용하지 않습니다. 각각의 컴퓨터나 브라우저의 local에 쿠키들은 저장됩니다.





How do i actually use them


쿠키는 모든 웹 프로그래밍 언어에 의해 접근될 수 있습니다. 이 의미는 자바스크립트, python, php 그리고 다른 많은 언어들이 쿠키를 다룰 수 있다는 거죠. 첫번째로 쿠키를 다루는 가장 쉬운 방법인 jQuery를 이용한 쿠키 다루기를 설명하겠습니다.

jQuery는 jQuery library와 함꼐 사용하는 plugin을 가지고 있습니다. (이 링크에서 받으실 수 없으시면 아래 파일을 받으세요.)


jquery.cookie.js


이 플러그인을 이용하시면 정말 쉽게 쿠키를 저장하고 또 거기에 접근하실 수가 있습니다. 그럼 쿠키를 저장하고 displaying 하는 부분의 코드를 볼까요.



  1. <html>  
  2. <head>  
  3. <script src="http://code.jquery.com/jquery-latest.js"></script>  
  4. <script src="jquery.cookie.js"></script>  
  5. <script>  
  6. $(document).ready(function(){  
  7.     // set cookie  
  8.     $.cookie('my_cookie_name', 'value inside of it');  
  9.   
  10.     // get cookie  
  11.     alert($.cookie('my_cookie_name'));  
  12.   
  13.     // delete cookie  
  14.     $.cookie('my_cookie_name', null);  
  15. });  
  16. </script>  
  17. </head>  
  18. <body>  
  19. <a class="setme">Set Me</a>  
  20. <a class="tellme">Tell Me</a>  
  21. <a class="delete">DeleteM</a>  
  22. </body>  
  23. </html>  



이제 코드의 중요한 부분을 살펴보죠. 첫번째로 jQuery를 embed 해야죠. 그 다음에 jquery cookie 플러그인을 add 했습니다. 그리고 저 아름다운 jQuery code를 시작합니다.


set cookie 하는 부분은 그냥 보시기만 하셔도 아시겠죠? 딱 한 줄 입니다. 그러면 my_cookie_name이라는 쿠키가 세팅 될 겁니다. 그 값은 value inside of it 이 되겠죠. 

$.cookie() 플러그인에 두개의 파라미터를 pass 했습니다. 이름과 값에는 작은 따옴표나 큰 따옴표를를 붙여야 합니다.


쿠키를 get 하는 방법도 아주 직관적입니다. 그냥 쿠키 이름을 pass 하시면 됩니다. jQuery 플러그 인에요. 그러면 우리가 저장한 값을 가지게 될 겁니다.

그리고 마지막으로 쿠키를 지우는 것은 쿠키를 저장하는 것과 거의 같습니다.

단지 다른것이 있다면 값에 null 을 넣으시면 됩니다.


Now let’s go more advanced


이제 쿠키를 세팅하고 값을 add 하고 저장된 값을 delete 하는 것 까지 다 했습니다.

이제 쿠키를 특정 시간 동안 저장하는 것 같은 혹은 특정 date 까지 저장하는 방법 같은 것을 알아보겠습니다.



  1. // cookie expires in 10 days  
  2. $.cookie('cookie_name''our value', { path: '/', expires: 10 });  
  3.   
  4. // cookie expires in a set JavaScript Date  
  5. var date = new Date();  
  6. $.cookie('cookie_name''our value', { path: '/', expires: date });  



첫번째 코드는 이 쿠키가 10일 이후에 expire 되도록 세팅한 겁니다. 이게 끝입니다. 정말 간단하죠. 세번째 파라미터에 쿠키가 저장 될 path를 넣습니다. 그리고 / 를 넣어서 깔끔하게 정리하시고 다음으로는 expiration days를 넣으시면 됩니다.


두번째 코드는 우선 date 변수를 만듭니다. 이 date 변수에는 현재 날짜가 들어갑니다. 그리고 이것을 특정 JavaScript date 에 expire 되게 쿠키에 세팅할 겁니다. real date를 넣으면 여러분이 그 javascript date를 넣을 때까지는 작동을 하지 않을 겁니다. 자세한 사항은 JavaScript date 에 대한 글을 읽어 보세요.


How to do this with JavaScript

아래에는 일반 자바스크립트에서 쿠키를 다루는 예제입니다.


  1. function setCookie(key, value) {  
  2.    var expires = new Date();  
  3.    expires.setTime(expires.getTime() + 31536000000); //1 year  
  4.    document.cookie = key + '=' + value + ';expires=' + expires.toUTCString();  
  5.    }  
  6.   
  7. function getCookie(key) {  
  8.    var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');  
  9.    return keyValue ? keyValue[2] : null;  
  10.    }  
  11.   
  12. setCookie('test''5');  
  13. alert(getCookie('test'));  



두개의 함수를 만들었습니다. setCookie와 getCookie 입니다. setCookie에는 두개의 변수를 pass 해야 합니다. key와 value 한 쌍이죠. 위 예제에서는 쿠키의 expire 날을 1년으로 잡았습니다. 물론 여러분이 바꿀 수도 있죠. 위에 javascript date에 대한 링크가 있죠? 거길 참조하세요.


이 글을 읽으시고 쿠키에 대해서 그리고 쿠키를 다루는 법에 대해서 감을 잡으셨기를 바랍니다.


======================================================


위 글은 jQuery Mobile 이 아니라 jQuery 에서 쿠키 관련 플러그인을 사용하는 법을 알려주고 있습니다.

하지만 jQuery Mobile에서도 같은 방법으로 이용하시면 됩니다.


예제를 하나 공부하려고 하는데 거기에 저 플러그인을 사용했길래 먼저 이 플러그인을 한번 훑어 봤습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고
이전 1 다음