Showing posts with label Jquery. Show all posts
Showing posts with label Jquery. Show all posts

Wednesday, May 9, 2012

jQuery Mobile on PhoneGap :: Cross-domain page request 설정

jQuery mobile 로 remote 서버의 페이지에 접근하는 경우는 두가지다.

1. ajax 처리

ajax처리는 javascript 혹은 jQuery로 간단히 처리할 수 있다.
아래의 jQuery 코드는 www.geference.com 의 exam.php를 실행하고 그 결과를 data로 받아 경고창에 뿌려준다.  jQuery mobile 에서도 잘 작동한다.


$.post( 'www.geference.com/exam.php' , function(data){ alert( data) } )




2. remote 서버 페이지로 페이지 이동

jQuery mobile 의 페이지 이동은 $.mobile.changePage() 함수가 담당한다.
하지만 아래의 코드는 제대로 작동하지 않는다.


$.mobile.changePage( 'www.geference.com/exam.php')



기본적으로 jQuery mobile은 cross-domain 페이지 이동이 안 되도록 설정 되어 있다.
cross-domain 페이지 이동을 가능케 하려면,  아래 설정을 app의 시동시에 등록해 두어야 한다.


$.support.cors= true;
$.mobile.allowCrossDomainPages = true;


phonegap 1.3.0 버전을 기준으로 테스트해 본 결과, $.support.cors 는 기본 설정이 true로 되어 있어, 따로 설정을 하지 않아도 되지만, $.mobile.allowCrossDomainPages 는 기본이 false로 되어 있어 명시적으로 true로 설정해 주어야 한다.

phonegap에서 white list 설정을 풀어주어야 하는 것도 잊으면 안 된다.

Monday, April 30, 2012

jQuery mobile :: content 영역 사이즈를 window 사이즈에 넘치지 않게 표시하는 방법

jQuery mobile 은 각 페이지 요소를 표현하는 CSS 설정이 default로 함께 딸려 있다. Prototype 용으로 이런 default 설정을 그대로 사용하는 것이 매우 편리하지만, 앱 디자인을 customize하기 위해선 default CSS 설정을 제거하고, 새롭게 CSS 를 설정해 디자인을 조정해야 한다.

본 post에서는 jQuery mobile 의 페이지 기본 요소인 header, content, footer 로 이루어진 페이지에서 이들 세 요소가 전체 화면 영역을 차지하도록 하는 한 가지 방법을 소개한다.



# jQuery mobile 의 기본 페이지 설정

<section data-role='page' >

  <div data-role=header >

      HEADER

  </div>

  <div data-role=content>

      CONTENT

  </div>

  <div data-role=footer>

     FOOTER

  </div>

</section>



구체적으로, header와 footer 를 설정하고 남은 영역을 content 가 완전히 차지하게 하는 것이 목표. 이 때 content가 차지하는 영역은 전체 화면 영역에서 header와 footer를 차지하는 영역을 제외한 나머지 영역을 단 1px 도 넘거나, 부족하지 않게 하는 것이 핵심이다.


방법1 :: Static  할당 
header와 footer 그리고 전체 화면 크기를 확인해보고, 전체 화면 크기에서 header와 footer를 제외한 영역을 px단위로 정확하게 <div data-role=content> 에 할당한다.

문제점: 서로 다른 모바일 기기들은 각기 다른 화면 사이즈를 가지는데, 이 방법을 이용한다면 각 모바일 기기들에 따라 서로 다른 content 영역 사이즈를 할당해야 하는데,  상당히 번거롭다는 점 뿐만 아니라, 현실적으로 존재하는 모든 device를 테스트 하기 어렵다는 근본적인 문제에 봉착한다.



방법2::  Dynamic 할당
 각 요소 사이즈를 javascript를 이용해 계산하고, content 사이즈를 할당하는 방법. javascript를 통해 동적으로 사이즈를 할당하기 때문에, 다양한 device에서도 제대로 된 영역의 사이즈를 계산하고 할당할 수 잇다.



Step 1) header와 footer 영역 사이즈 계산 
data-role=header, footer, content 모두에 padding 값이 설정되어 있다. 요소가 차지하는 전체 사이즈는 height + padding + border 이기 때문에 header와 footer 가 차지하는 공간을 계산하기 위해서는 height+padding+border 를 계산해주는 jquery의 outerHeight 메소드를 이용한다.



var head_height=$('[data-role=header]').outerHeight();

var footer_height=$('[data-role=footer]').outerHeight();




Step 2) Content 영역의 default CSS 제거 
content 영역의 padding, border 사이즈를 고려하여 height 를 알아내고, height 사이즈 만을 변경할 수도 있지만, 이 보다는 default padding, border 사이즈를 0으로 두고, height 사이즈를 변경하고, 필요하면 이후 다시 padding, border 를 CSS 를 이용하여 할당하는 쪽의 코드가 더 간결하고 명확하다는 개인적인 생각이다. 따라서 여기서는 content의  default CSS 를 제거한다.



# content 의 default padding, border 사이즈를 0으로 설정한다.

div[data-role=content]{

  padding:0;

  border:0

}




Step 3) header와 footer 가 차지하는 영역을 제외한 영역을 height가 차지하도록 설정
앞서 계산한 header와 footer 의 영역을 제거한 나머지 공간을 content가 차지하도록 설정을 한다.


  # 전체 화면의 높이 $(document).height() 에서 앞서 계산한 head와 footer의 높이를 뺀 공간의 높이를 계산하고 이를 content 영역의 높이로 설정

  var content_height= $(document).height() - head_height - footer_height ;

 $('[data-role=content]').css('height', content_height+'px');




Tuesday, March 20, 2012

jQuery:: Namespaced event

Javascript, jQuery 에서 하나의 event에 여러개 handler function을 연결하고 컨트롤 할 수 있다.
이를 좀 더 쉽게 사용할 수 있도록 jQuery에선 Namespaced Event 기능을 제공한다.
간단히 요약하자면 event와  handler 의 '연결'을 class 로 name을 주고 이를 컨드롤 할 수 있게 하는 형태다.

흔히 쓰이는 event와 handler 연결 형태는

 $('#button').click( handler1 );
 $('#button').bind('click', handler2);
 $('#button').bind('click', handler3);

와 같은 형태인데, 위의 경우엔 id=button인 element를 클릭하면 handler1, 2,3 세개 handler 함수가 동시에 호출 된다. 경우에 따라서 handler 들을 개별적으로 컨드롤 해야할 경우가 생긴다. 이런 경우 namespaced event 를 사용하면 매우 편리하다.


사용자 로그인 전과 후의 기능을 차별화 하려고 하는 상황을 가정해 보자.
버튼 A를 누르면

1. 로그인 전에는

  • 로그인 창을 띄워준다.
  • 버튼 색깔을 빨간색으로 지정한다.

2. 로그인 후에는

  • 버튼 색깔을 빨간색으로 지정한다. 
  • 사용자 정보 창을 띄워준다. 
아래와 같이 버튼이 지정되어 있다면,

<button id="login">Button</button>


로그인 전 버튼 클릭이 담당하는 모든 handler 함수를 버튼에 연결하고,

 $('#login').bind('click.loginPageShow', loginPage );
 $('#login').bind('click.changeColor',changeColor );



로그인 하는  경우 로그인 페이지 창 띄우는 handler를 버튼 '클릭' event에서 삭제하고, 사용자 정보 창 띄우는 handler를 버튼에 아래와 같이 연결할 수 있다.

 if( login() ) {
    $('#login').unbind('click.loginPageShow' );
    $('#login').bind('click.showUserinfo',showUserinfo );
 }

Friday, February 10, 2012

jQuery 에서 동적 이벤트 등록시 이벤트 중복 문제

Javascript 에서 addEventListener 그리고 jQuery에서 .bind , .click 등 으로 다양하게 이벤트를 등록할 수 있다. 하지만, 어떤 DOM에 이벤트가 등록되는지에 따라 이벤트는 원하는 대로 동작하지 않는 경우가 발생할 수 있다. 몇가지 상황을 들어 본다.

1. 동적으로 생성되는 DOM에 대한 이벤트 등록
동적으로 새롭게 생성되는 이벤트에 대한 등록은 상대적으로 안전하다고 본다. 생성되는 이벤트에 대해 이벤트가 1:1로 등록이 되게 코딩을 한다는 가정 하에서. 하지만, DOM이 여러번 생성되고 동적 생성시 동적 삭제가 제대로 동반되지 않을 때 문제가 발생할 수 있다.

$('#create').click( function(){
     $('<div id=button >Button</div>').appendTo('body');
     $('#button').click( function(){
          alert('good');
     });
  });

위의 코드는 어떻게 동작할까? create 을 누르면 id=button인 버튼이 생성이 되고, 버튼을 누르면 'good' 이란 문구를 띄우는 창이 발생하는 이벤트가 등록된다. create를 두번 누르면 어떻게 될까?

버튼이 하나더 생긴다! 하지만, 새로 만들어진 버튼에는 이벤트가 등록되지 않는다. 동시에 처음에 만들어졌던 버튼을 누르면 alert 창이 두번 뜬다. id=button를 가진 첫번째 엘리먼트에 이벤트가 등록되므로 이후로 만들어지는 버튼에는 이벤트가 등록되지 않는다.

id 가 같은 엘리먼트가 여러개 만들어지는 건 피해야하지만, 그럼에도 불구하고 굳이 이 상황을 해결하고 싶다면, 즉 만들어지는 버튼 각각에 대해 이벤트를 등록하고 싶다면? 아래와 같이 각 엘리먼트 발생시 직접 이벤트를 연결해주면 된다.

$('#create').click( function(){
     $('<div id=button>Button</div>').appendTo('body').click( function(){
          alert('good');
     });
  });

2. 존재하는 DOM에 대한 이벤트 등록
보통 문제는 존재하는 DOM에 대한 이벤트 등록이다.
$('#button').click( function(){
       $('#start').click( function(){
               alert('What?');
       });
  });

위의 코드는 버튼( id=button인 엘리먼트)을 클릭하면, id=start 인 엘리먼트에 alert 를 띄우는 이벤트를 등록한다. 버튼을 한번 누르고 나면 이후에 start 를 눌렀을 때, 한번 alert 창을 띄운다, 이것이 이 코드를 작성한 사람의 의도일 것이다.

그런데 버튼을 두번 누르면 어떻게 될까?

start 엘리먼트에 이벤트가 두번 등록된다. 그래서 start 를 누르면 두번 alert 창이 뜬다. 한번 더 버튼을 누르면? 당연히 세번 alert 창이 뜬다.
이 문제를 해결하는 가장 간단한 방법은 버튼을 누를 때 마다 아래와 같이 기존에 등록된 'click' 이벤트를 제거하는 것이다.

$('#button').click( function(){
       $('#start').unbind('click');
       $('#start').click( function(){
               alert('What?');
       });
  });

기본적으로 동적 생성되는 DOM 이 아닌 경우라면 이벤트 등록을 중복하지 않는 것이 후폭풍을 막는 지름길이 아닐까 생각하고, 써야하는 상황이라면 항상 이벤트 중복이 되지 않게 주의를 기울여야 함을 기억해 놓자!!

Thursday, September 1, 2011

jQuery::이미지 크기 동적으로 변경

아래와 같이 이미지를 표현하고 난 후,

<img src='yes.jpg'>


상황에 따라 이미지 사이즈를 동적으로 변경해야 하는 경우가 종종 발생한다.
한 예로, 이미지의 가로와 세로의 길이를 비교해서 긴 쪽 이미지를 100px 로 바꾸는 경우를 jQuery 를 이용하면 어떻게 될까.


var img=$('img');
if( img.width()  > img.height() ) {
   img.width('100px');
}else{
  img.height('100px');
}


작동해야 할 것 같은 이 코드는 원하는 대로 작동하지 않는다.
원인은 이미지가 완전히 로딩되지 않은 상태에서 이미지의 가로, 세로 길이를 비교했기 때문이다. alert 를 이용해 img.width() 와 img.height() 를 찍어보면 값은 0으로 나온다.

따라서 위의 코드를 이미지가 완전히 로딩되고 난 이후에 동작하도록 고쳐야 한다.
load 함수를 이용해 이를 고려한, 완전히 동작하는  코드는 아래와 같다.



var img=$('img');

img.load( function() {
   if( img.width()  > img.height() ) {
     img.width('100px');
   }else{
     img.height('100px');
   }
}



PS::
위의 코드를 이용한 이미지 사이즈 변경은 한가지 문제점을 가지고 있는데,
.load 함수의 실행은 이미지가 완전히 로딩된 후에 일어난다는 사실이다.

즉, 큰 이미지가 로딩되어 화면에 표시된 후( 네트웍 속도가 느릴 수록 이 효과는 극대화),
load 함수에 따라 이미지 리사이징이 일어난다.
문제 해결은간단한데, .load 함수 이전에 이미지 표시를 막으면 된다.

1. css 파일에 이미지 표시를 하지 않는 것으로 default 설정을 한다.

img{
  visibility:hidden;
} 


2. .load 함수에서 이미지 표시 제한을 풀어준다.

img.load( function() {
   if( img.width()  > img.height() ) {
     img.width('100px');
   }else{
     img.height('100px');
   }
   img.css('visibility','visible');

}

Monday, March 1, 2010

Jquery이용한 dynamic 페이지 스타일

Javascript 라이브러리인 Jquery를 이용하면, 간단하게 복잡한 Javascript 기능을 구현할 수 있다.
최근에 간단한 웹DB를 만들면서 로딩된 page에 CSS 스타일을 적용하는 기능을 구현하였는데, Jquery( 및 Javascript) 를 이용할 때, 주의해야할 사안에 실수를 저지르는 바람에 한참 삽질을 했는데, 이를 정리해 본다.

먼저 아무런 내용이 없는 html 구조를 아래와 같이 설정하자.
(이 페이지의 html코드에서 html tage (<, >) 가 허용이 안되어, tag 괄호를 <> 대신 () 를 사용하였다. )

(html)
(div id="main")

(/div)
(html)


그다음 Jquery를 이용해서, id=main 부분에 외부 html 파일을 읽어 뿌려주는 부분을 html head부분에 script로 추가한다.

(script)
$(document).ready(function(){
$(#main).load('content.html');
});
(/script)



* 여기서 첫번째 문제, load된 html 내용에 원 html 파일에 적용된 CSS 가 적용될까?
적용된다. 페이지에 설정된 CSS 이기 때문에 load되어 원 페이지의 CSS 규칙 적용을 받는 내용에도 CSS 규칙이 적용된다.

다시 page로 돌아가서, 이번에는 load된 html의 특정 div id 를 가진 부분에 대해 CSS 규칙을 추가한다.

(script)
$(document).ready(function(){
$(#main).load('content.html');
$('#top').addClass('css_top'); //id=top에 CSS 규칙 css_top을 적용한다.
(/script)



* 여기서 두번째 문제, load된 html의 특정 부분에 CSS 규칙이 적용될까?
정답은 조건적으로 그렇다 이다. 문제는 네트워크 지연에 있다. AJAX방식의 모든 구현에서 발생하는 문제로, script에서는 load 이후, css가 추가되는 것 처럼 보이지만, 실제 html이 load되는 시점은 html을 읽어오는 동안의 '지연' 이 발생하므로 css 추가 부분이 적용된 이후가 될 수 있다. 이런 경우엔 css 규칙 적용 부분이 먼저 실행되고 html이 로딩이 되었기 때문에, css 규칙 추가가 이루어 지지 않는다.

실제로는 plain html 파일인 경우, 지연효과가 미미하여, 이 문제가 발생하지 않을 수 있는데, 내가 작업하는 상황에서는 읽어오는 파일이 그 자체로 Mysql 을 긁고 processing 을 하여 조금 시간이 걸리는 php 파일이었기 때문에, 이 문제가 발생하였다.

이런 상황에서 문제없이 순서대로 원하는 기능을 구현하기 위해서는 '콜백' 기능을 이용해야 한다. 즉 각 jquery 라인을 순서대로 실행하도록 조건을 걸어두는 것이다.

콜백 기능 구현은 간단한데, 위의 상황에서 html 파일을 load하고 난 이후, css 규칙을 추가하는 콜백 함수를 구현하면, 원하던 기능을 문제없이 수행할 수 있다.


(script)
$(document).ready(function(){
$(#main).load('content.html', function(){
$('#top').addClass('css_top');
});
});
(/script)