postMessage를 이용한 크로스도메인간 iframe 리사이징

기본

회사에서 외주를 주고 있는 사이트가 변경돼서, <iframe>으로 해당 사이트를 임베드 해야하는 이슈가 있었습니다. <iframe> 해서 추가하는 거야 일도 아닌데 포함시킬려는 페이지의 사이즈에 맞게 사이즈를 조절해 줘야 하더군요.

바꾸기 전에는 같은 도메인이었기 때문에 iframe 안에서 부모쪽의 함수를 호출하면 되는 부분이었는데 도메인이 아예 달라져서 이렇게 호출하려고 하면 크로스도메인 관련 오류가 떨어집니다.

이 문제를 해결하기 위해 몇 가지 트릭이 존재하는데 그 중에서 제가 찾은 가장 모던한 방법은 window.postMessage를 사용하는 겁니다.

일반적으로 서로 다른 페이지의 스크립트가 통신하기 위해선 프로토콜, 포트, 호스트(도메인)가 같아야만 가능한데 window.postMessage는 이런 제약들을 우회할 수 있다고 합니다. 그러면 보안이 문제가 될 수도 있는데 이게 다른 페이지의 메소드를 호출하는건 아니고 한쪽에선 메시지를 보내고 다른쪽에서 그 메시지를 처리하는 일종의 이벤트 이고 받는 쪽도 origin을 지정할 수 있기 때문에 보안에 큰 문제는 없어 보입니다. (단, jQuery postMessage 플러그인을 사용할 경우 window.postMessage를 지원하지 않는 브라우저에서는 origin이 무시됩니다.)

문제는 IE 8+ 부터 지원한다는 건데 다행히 jQuery postMessage 플러그인을 사용하면 IE6도 커버가 됩니다. 코드도 간단합니다. ajax 요청과 크게 다르지 않네요. window.postMessage를 지원하지 않는 경우엔 window.location에 해시(#)를 붙여 메시지를 보내고 window.location.hash 값을 모니터링하는 식으로 처리합니다. 기발하네요.

Advertisements

최근 프로젝트 진행하며 사용한 유용한 jQuery 플러그인

기본

1. jQuery Placeholder

HTML5에 등장한 속성인 placeholder는 폼에 디폴트 문구를 표시할 수 있어 매우 유용합니다만.. IE에서 제대로 보여주지 못하는 치명적인 단점이 있습니다. 이를 보완할 수 있는 jQuery 플러그인! 사용법도 상당히 쉽습니다. placeholder 속성에 원하는 기본 문구를 작성한 후.. placeholder()를 뙇!

$("input").placeholder();
<input type="text" placeholder="Foobar"/>

2. jQuery Create Event

live() 함수가 deprecated 되긴 했지만.. 프로젝트에서 1.4.x 버전을 사용하기 때문에 별 고민 없이 사용한 플러그인 입니다. 이 플러그인은 live() 함수에서 “create” 이벤트(DOM에 새로 엘리먼트가 추가된 경우)를 감지할 수 있게 합니다.

$("someDiv").live("create", function(...));

Ajax로 서버에서 데이터를 받아온 후, 특정 부분이 업데이트 됐을 경우 어떤 행동을 해야한다면 이 플러그인을 써보세요.

3. jQuery Data Selector

jQuery API 중에 해당 DOM에 객체를 저장할 수 있는 data() 함수가 있습니다. 간단하게 key/value로 이루어져 있는데요. jQuery Data Selector 플러그인은 jQuery 셀렉터에 data()로 저장한 key/value를 검색할 수 있게끔 확장해 줍니다.

$(function(){
    // Attach data to the 2nd li
    $('#dataSelector li').eq(1).data('foo', 'bar');
    // Change the color of the li whose foo key is == bar
    $('#dataSelector li:data(foo=bar)').css('color', 'red');
});

4. jQuery Wordcount

트위터 글 입력 폼 같이 사용자가 몇 글자 입력했는지 알아보려고 textarea를 만든 다음에 keyup, keydown, keypress 같은 이벤트를 걸고 크로스브라우징 테스트를 해보면 특정 브라우저에서 생각대로 잘 동작하지 않습니다. 아쉬운 일이지만 브라우저에서 한글 키 입력 이벤트를 제대로 처리하지 못하기 때문인데요. 이를 보완하기 위해 타이머 이벤트로 특정 시간 마다 글자 수를 체크해서 업데이트 하는 플러그인을 만들어 봤습니다. 처음으로 만든 jQuery 플러그인이네요 ㅋ

사용법은 나름 간단합니다:

$("textarea").wordcount({
    countElement: $("span")
});
이번 프로젝트 진행하면서 만든 플러그인이 하나 더 있었네요! 두 번째 플러그인이군요. 이 플러그인은 jQuery UI Datepicker 예제에 나와있는 날짜 범위 선택을 재사용 하기 쉽게 만든 플러그인 입니다. 소소한 제한사항이 있으니 코드에 있는 주석을 꼭 읽어보세요.
사용법은 이런식입니다:
$("#from, #to").datepickerRange();
자매품으로 class 셀렉터를 사용할 수도 있습니다:
$(".from, .to").datepickerRange({
    dateFormat: "yy-mm-dd"
});
혹시 사용하다가 이상한 점을 발견하시면 이슈 등록 부탁드려요! (이 포스팅의 목적)

jQuery의 event.stopPropagation()

기본

회사 코딩하던 중에 다음과 같은 문제에 봉착했습니다:

제공받은 마크업 셀렉트 박스가 있는데 마치 콤보박스같이 클릭하면 아래로 몇 개의 리스트가 나타납니다. 따라서 제목을 클릭했을 때 리스트가 나타나고 사라져야하며, 또한 셀렉트 박스 외의 다른 지점을 클릭했을 경우 리스트가 사라져야 합니다.

처음엔 focusout()을 사용해보려고 했는데 제목을 누른 후 나타난 리스트를 클릭할 경우 focusout  이벤트가 발생해 리스트를 클릭할 수가 없습니다. 그래서 body에 click() 이벤트를 걸어서 해당 리스트를 hide() 하려고 했더니 모든 클릭 이벤트를 먹어서 제목을 클릭했을 때 리스트가 나타나질 않습니다.

팀원 분에게 물어보니.. 팀장님이 그럴 때 stopPropagation()을 사용하라고 하시더라구요. 사실 그동안 많이 봤던 함수인데 무슨 기능 하는지 모르고 있었습니다. 무슨 기능인고 하니, 이벤트가 발생하면 버블링(트리를 타고 올라가서)해서 루트까지 올라가게 되는데 이를 막아주는 기능이라고 합니다. 즉, 셀렉트 박스의 제목에 걸어두면 body의 click() 이벤트 핸들러로 가는걸 막아주며, 따라서 원래 제목에 걸어둔 이벤트 핸들러가 동작하게 됩니다.

그래서 다음과 같이 stopPropagation()을 먼저 해줘야 합니다.

$(“#listBoxTitle”).click(function(e) {

e.stopPropagation();

// 하고 싶은 것

});

같은 맥락의 delegate() 라는 함수가 있는데, 이 함수로 특정 엘리먼트에 이벤트 핸들러를 등록해두면 DOM 트리 상 하위에 있는 엘리먼트가 버블링 시키는 이벤트를 document까지 안올리고 여기서 처리하게 됩니다.

그나저나 jQuery 1.7 에선 live, delegate 함수 모두 on() 으로 통합되었다는 군요.

IE6 button 태그에서 preventDefault() 안됨

기본

IE6에서 jQuery로 <button> 태그에 이벤트 핸들러를 바인드 할 때, event.preventDefault() 를 사용하면 에러가 발생합니다.

그래서 다음과 같은 폴백으로 넘겼습니다:

if (event.preventDefault)

event.preventDefault();

else

event.returnValue = false;

jQuery Template 이슈 몇 가지

기본

프로젝트 진행 중에 플래시 <object> 태그 템플릿을 만들어 놓고 몇 가지 애트리뷰트를 바꿔치기 해야하는 이슈가 있었습니다. 이렇게 완성된 <object> 태그를 jQuery Dialog에 보여주면 사용자가 그걸 긁어서 다른 곳에 붙일 수 있게 하는 일이었죠. 대수롭지 않게 생각했었는데 그냥 붙이면 파싱돼서 다이얼로그 창에 플래시가 떠버리더라구요.

문자들을 이스케이프 하면 해결할 수 있는 일이었지만, 이걸 서버에서 해야하는지 아니면 뷰에서 해야하는지.. 고민을 하다가 간단한 템플릿이었기 때문에 뷰에서 하기로 마음 먹었습니다.

처음에는 <div> 태그 안에 살짝(?) 이스케이프 한 템플릿을 넣어 놓고 자바스크립트로 치환했었는데요. 최신 브라우저에선 문제 없이 잘 됐지만 IE에서는 <object> 태그 안에 템플릿에 없던 속성을 추가, 템플릿과 다른 값을 대입, 템플릿 바깥에 있는 태그(body, html 등)를 같이 가져오는 문제가 생겼습니다 😦

그러다가 발견한 게 jQuery Template.

구글링 하다보니 아대장님의 소개글도 찾을 수 있었습니다. 베타버전이고 현재 이 링크들에 걸려있는 템플릿 플러그인은 프로젝트가 중지된 상태입니다. 현재는 jQuery UI에서 작업이 진행중이라고 하는데 아직 공개되진 않은 것 같습니다.

이 beta API를 사용해서 결과적으로 IE와의 호환성 문제는 해결했지만 몇 가지 이슈가 있었습니다.

회사에서 NHN의 Jindo 프레임워크를 전사적으로 사용 중인데요. 진도에서도 $를 사용하기 때문에 jQuery와의 충돌을 막기 위해 다음과 같은 처리를 해줍니다:

var $J = jQuery.noConflict();

$J로 jQuery를 사용할 수 있죠. 문제는 jQuery 템플릿에서 치환되는 부분에 ${ } 문법을 사용한다는 것입니다. 저는 처음에 이 부분을 $J{ }로 해줘야 하나? 하고 생각했었는데 그건 아니었습니다. 그냥 ${ } 이런식으로 ㅋ

그리고 ${ } 이것은 EL과 같기 때문에 jsp를 사용하면 먼저 파싱돼버려서 템플릿이 바껴버립니다. 헐.. 그래서 \$ 이런식으로 $ 자체를 이스케이프 해버리면 { } 요것은 그냥 일반 문자가 돼버리기 때문에 템플릿의 ${ } 부분을 \${ } 부분으로 치환을 했었는데요. 이게 테스트 할 때는 문제가 전혀 없었는데 서버에 있는 구버전 Tomcat 5에서 \$를 처리하지 못하고 validation 에러를 내버리더라구요 ;ㅁ;

결국엔 아래와 같은 꽁수로 상황을 모면했습니다:

<c:set var=”S” value=”$”/>

<script id=”template” type=”text/x-jquery-tmpl”>

… ${S}{url} …

그리고 <object> 태그안에 들어있는 <, > 문자를  &lt;, &gt;로 바꿔줬더니 IE 호환성 문제도 해결이 되더라구요. 어쨌든 매력적인 플러그인임에는 틀림 없지만 시작을 마이크로소프트에서 해서 그런지 몰라도 EL과 같은 ${ } 사용은 차후 버전에서는 달라졌으면 하네요.