'JavaScript'에 해당되는 글 33건

  1. 2011/04/08 xui.js - 모바일 html5 웹앱을 위한 초경량 자바스크립트 라이브러리
  2. 2011/03/13 웹에서 아이폰스러운 Carousel 구현하기
  3. 2011/03/13 터치기반 모바일 웹킷에서 버튼 반응 속도 개선하기
  4. 2010/11/18 HTML5/CSS3/JavaScript로 아이폰 앱 만들기 - XCode 프로젝트 템플릿 (1)
  5. 2010/11/16 HTML5/CSS/JavaScript로 안드로이드 "앱" 만들기
  6. 2010/11/14 HTML5/CSS/JavaScript로 아이폰 "앱" 만들기 (6)
  7. 2010/10/08 Jo HTML5 Mobile Application Framework 초간단 리뷰
  8. 2009/12/10 JavaScript Common Mistakes(3) - 다른 언어에 익숙한 개발자들이 하기 쉬운 실수
  9. 2009/12/09 JavaScript Common Mistakes(2) - This "this" is not the "this" (2)
  10. 2009/12/08 JavaScript Common Mistakes (1) - Async! Async! Async! (10)
  11. 2009/08/24 심심풀이 코딩 - 자바스크립트로 만든 벽돌깨기~ (7)
  12. 2009/01/07 Dojo Objective Harness를 이용한 웹 2.0 애플리케이션 단위 테스트
  13. 2008/10/24 전문가다운 Ajax 애플리케이션 개발, Part 3: DWR, 자바, Dojo 툴킷을 사용하여 자바와 자바스크립트 통합하기
  14. 2008/10/08 Dojo Toolkit 1.2 버전 릴리즈 (1)
  15. 2008/10/05 Ajax로 사이트 전면 개편, Part 4: 기존 사이트를 jQuery와 Ajax forms를 사용하여 개선하기
  16. 2008/09/23 Ajax로 사이트 전면 개편, Part 3: jQuery, Ajax 탭, 회전식 슬라이드쇼로 기존 사이트 개선하기 (2)
  17. 2008/08/20 dojo by example(7) - object system
  18. 2008/08/10 dojo by example(6) - 이벤트 시스템 (2)
  19. 2008/08/06 전문가다운 Ajax 응용 프로그램 개발, Part 1: Prototype 자바스크립트 라이브러리와 script.aculo.us 사용하기
  20. 2008/08/02 dojo by example(5) - 애니메이션/효과
  21. 2008/07/29 dojo by example(4) - 유틸리티 함수
  22. 2008/07/24 dojo by example(3) - 유틸리티 함수 (2)
  23. 2008/07/20 웹 프로젝트에서 jslint로 자바스크립트 검증하기: maven 또는 ant
  24. 2008/07/19 dojo by example(2) - 유틸리티 함수 (2)
  25. 2008/05/13 자바스크립트의 encodeURI와 친구들~ (3)
  26. 2008/03/15 IE8에 대처하는 우리의 자세... (2)
  27. 2007/12/04 dojo에서 $ 쓰기
  28. 2007/11/16 prototype사용자를 위한 dojo 입문 (4) (1)
  29. 2007/11/15 prototype사용자를 위한 dojo 입문 (3)
  30. 2007/11/13 prototype사용자를 위한 dojo 입문 (2)
hacking/web2011/04/08 13:20
크리에이티브 커먼즈 라이선스
Creative Commons License

xui.js 초간단 리뷰


요약

xui.js는 모바일 html5 웹앱에 특화된 초경량 자바스크립트 라이브러리

특징

  • 초경량(9.4k) - jquery 최소 29k, dojo 최소 31k, jQueryMobile 최소 135k, Sencha Touch 최소 524k, …
  • 단순 명쾌하고 익숙한(jQuery 스타일의 메소드 체이닝) 문법
  • 모바일에 최적화(webkit, ie mobile, blackberry)
  • 제약없는 오픈소스 라이센스(MIT; Sencha의 듀얼 라이센스 대비 장점)

개발 배경

NitobiPhoneGap 용으로 개발한 자바스크립트 라이브러리.

기능 요약

아래에, xui.js가 제공하는 모든(!) 함수를 간략하게 설명합니다. 개발자 분들의 이해를 돕기 위해 대응하는 jquerydojo의 함수도 같이 소개 했습니다.

기본 함수

  • extend(object)
    • 프로토타입 상속
    • [ jquery.extend(), dojo.extend() ]
  • find(selector, context)
    • css 셀렉터에 부합하는 노드 선택.
    • [ jquery.find(), dojo.query() ]
  • set(array)
    • 명시적으로 노트 선택.
  • reduce(elements, index)
    • 중복 제거
    • [ jquery.unique() ]
  • has(selector)
    • css 셀렉터에 부합 여부 확인
    • [ jquery.has(), dojo.query() ]
  • filter(fn)
    • 노드 필터링(제외).
    • [ jquery.filter(), dojo.filter() ]
  • not(selector)
    • css 셀렉터에 부합하지 않는지 확인.
    • [ jquery와 dojo의 not() css selector ]
  • each(fn)
    • 노드 순회
    • [ jquery.each(), dojo.forEach() ]

DOM 조작 함수

  • html(location, html)
    • HTML 컨텐츠 조작.
    • location: inner,outer,top,bottom,remove,before,after 중의 하나(생략가능; 생략하면 inner). 동일한 이름을 가진 단축함수(inner(html) 등) 사용 가능.
    • [ jquery.html(), dojo.place() ]
  • attr(attribute, value):
    • HTML 속성 조작.
    • value를 생략하면 get.
    • [ jquery.attr(), dojo.attr() ]

이벤트 함수

  • on(type, fn)
    • 이벤트 핸들러 등록.
    • type: click, load, touchstart, touchmove, touchend, touchcancel, gesturestart, gesturechange, gestureend, orientationchange 등. 동일한 이름을 가진 단축함수(예: click() 등) 사용 가능.
    • [ jquery.bind(), dojo.connect() ]
  • un(type, fn)
    • 이벤트 핸들러 등록 해제.
    • fn을 생략하면 해당 이벤트에 등록된 모든 이벤트 핸들러 등록 해제.
    • [ jquery.unbind(), dojo.disconnect() ]
  • fire(type, data)
    • 가상의 이벤트 발생.
    • data: 이벤트 핸들러로 전달되는 event 객체의 data 속성으로 전달(생략 가능).
    • [ jquery.trigger() ]

화면 효과 함수

  • tween(properties, callback)
    • css 속성 인비트윈(inbetween) 에니메이션.
    • properties: 에니메이트할 css 속성-값 pairs과 duration, after, easing 등의 추가 속성들 또는 속성들의 배열.
    • [ jquery.animateProperty(),  dojo.animateProperty() 등 ]

CSS 스타일 함수

  • setStyle(property, value)
    • css 속성 설정.
    • [ jquery.css(), dojo.style() ]
  • getStyle(property, callback)
    • css (계산된)속성 얻기.
    • [ jquery.css(), dojo.style() ]
  • addClass(className)
    • css 클래스 추가.
    • [ jquery.addClass(), dojo.addClass() ]
  • hasClass(className)
    • css 클래스 확인.
    • [ 참고: jquery.hasClass(), dojo.hasClass() ]
  • removeClass(className)
    • css 클래스 제거.
    • [ jquery.removeClass(), dojo.removeClass() ]
  • css(properties)
    • css 속성 일괄 설정.
    • [ jquery.css(), dojo.style() ]

XHR(AJAX) 함수

  • xhr(loation, url, options|fn)
    • AJAX 요청.
    • location: 결과(responseText)를 반영할 노드(생략 가능).
    • options: method, async, data, callback 등의 추가 속성 지정(생략 하거나 callback 함수만 지정 가능).
    • [ jquery.ajax(), ajax.load(), ajax.get(), ajax.post(), dojo.xhr(), dojo.xhrGet(), dojo.xhrPost()  등 ]

결론

xui.js는 jquery나 dojo 등의 기존 자바스크립트 라이브러리에서 널리 사용되지 않는 기능들과 다양한 데스크탑용 브라우져 지원을 위한 부가적인 코드를 제거하고, 자주 사용되는 함수들과 모바일 환경에서 꼭 필요한 브라우져만 지원하도록 최적화된 자바스크립트 라이브러리 입니다. 장단점을 요약하면 다음과 같습니다:
  • PROS: 크기, 성능, 구성, 소스 코드 품질
  • CONS: UI 툴킷 부재. 데스크탑 브라우져 호환성 부재. 문서 / 사용자 커뮤니티  부재.

직접 UI 툴킷을 만들 게 아니라면, 별도의 UI 툴킷을 사용해야 하므로 작은 크기로 인한 장점이 오히려 단점이 됩니다. JQueryMobile을 쓰려면 결국 jQuery가, Sench Touch를 쓰려면 결국 ExtJS가, Dijit(Dojo Widget)을 쓰려면 결국 dojo가 필요하게 되는데, 말 그대로 배보다 배꼽이 더 큰 상황이 됩니다. 또한, 데스크탑 브라우져 호환성이 부족하므로 xui.js는 모바일 웹에만 적용하고, 데스크탑 웹을 위해 별도의 자바스크립트 라이브러리를 사용해야 하므로 2중의 학습/개발이 필요하므로 장점보다는 단점이 커 보입니다.

여러 측면을 고려할 때, 새로운 모바일 웹 UI 툴킷을 자체 개발하거나, 새로운 범용 자바스크립트 라이브러리를 자체 개발한다면 좋은 기반(혹은 참고)가 될 수 있겠지만, 기존의 범용 자바스크립트 라이브러리(jquery, prototype, dojo 등...)의 대체품으로는 부적합 -_-;

저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2011/03/13 17:05
크리에이티브 커먼즈 라이선스
Creative Commons License

웹에서 아이폰스러운 Carousel 구현하기


페이지 컨트롤(UIPageControl; Carousel; 일명 회전목마 컨트롤)은 아이폰이나 안드로이드폰을 쓰면 가장 먼저 접하게되는 UI 컨트롤이다. 일명 홈 스크린이라고 불리는 화면에서 가로 또는 세로로 플리킹(flicking)하면 이전/다음 페이지로 이동하는 그 컨트롤이다. 아이폰의 경우에는 화면 하단에 하얗고 까만 작은 동그라미가 있고, 안드로이드는 화면 상단 좌우에(폰에 따라 조금씩다르다) 작은 동그라미가 있어서, 총 몇 페이지 중에서 몇 번째 페이지를 보고 있는 지를 알려준다.

이 글에서 설명하는 방법을 안드로이드용 푸딩얼굴인식 앱을 만들면서 활용했는데, 데모 동영상에서 35초와 1분 10초 근처에 나오는 화면이 이 컨트롤을 활용한 것이다.

백문이불여일견! 코드를 살펴보자!
$(document).ready(function() {
var iscroll = new iScroll('wrapper', {
snap: 'li',
momentum: false,
hScrollbar: false,
vScrollbar: false,
onScrollEnd: function() {
$('#indicator li').each(function(i, node) {
if(i === iscroll.currPageX) {
$(node).addClass('active');
} else {
$(node).removeClass('active');
}
});
}
});
iscroll.scrollToPage(0);
});

#wrapper {
width:200px;/*=page_width*/
height:200px;/*=page_height*/
margin:0;
padding:0;
overflow:none;
background-color:#fff;
}

#scroller {
position:relative;
top:0;
left:0;
width:600px;/*=number_of_page*page_width*/
height:200px;
float:left;
}

#scroller ul {
list-style:none;
position:relative;
display:block;
margin:0;
padding:0;
top:0;
left:0;
width:100%;
height:100%;
}

#scroller li {
display:block;
float:left;
width:200px;
height:200px;
}
/* 나는 깜찍한 CSS로 아이폰스러운 페이지 인디케이터를 구현하였으나 공간이 부족하여 생략한다 -_-; */

 <div id="wrapper">
   <div id="scroller">
     <ul>
       <li><div>1st page!</div></li>
       <li><div>2nd page!</div></li>
       <li><div>3rd page!</div></li>
     </ul>
   </div>
 </div>
 <div id="indicator">
   <ul>
     <li><span>1</span></li>
     <li><span>2</span></li>
     <li><span>3</span></li>
   </ul>
 </div>


백문이불여일RUN! 결과를 확인하자!(위에서 생략했던 깜찍한 CSS도 포함되어 있음)
http://jsbin.com/epeci5


이 글에서는 iScroll 라이브러리를 활용하여 페이지 컨트롤을 구현하고, 덤으로 아이폰과 유사한 인디케이터 까지 구현해 보았다.

모바일 단말은 화면이 작기 때문에 이런 유형의 컨트롤(탭/Carousel/...)들이 꽤 다양하고, 또 유용하지만, 직접 만들자면 쉽지 않다. 그렇다고 이 컨트롤 하나 때문에 Sencha나 jQueryMobile 같은 덩치 큰 프레임웍을 사용하는 것이 부담스럽다면, iScroll 라이브러리는 한 번 쯤 살펴볼 가치가 있다.

참고자료:
http://cubiq.org/iscroll-4
https://github.com/blackdynamo/jQuery-Mobile-Carousel
http://dev.sencha.com/deploy/touch/docs/?class=Ext.Carousel
http://www.winktoolkit.org/documentation/module/592/
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIPageControl_Class/Reference/Reference.html
저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2011/03/13 15:19
크리에이티브 커먼즈 라이선스
Creative Commons License

터치기반 모바일 웹킷에서 버튼 반응 속도 개선하기


아이폰/아이패드/아이팟의 모바일 사파리와 안드로이드의 모바일 크롬 등은 모두 터치기반 모바일 웹킷을 사용하는 브라우져들이다. 이 브라우져들은 버튼 등을 눌렀다(touchstart) 떼도(touchup) 즉시 반응(click)하지 않는데, 그 이유는 연속되는 터치 동작(touchstart-touchmove-touchend)들이 제스쳐(swipe, long click, …)인지 여부를 확인하기 위해 최대 300ms의 지연시간이 생기기 때문이다. 모바일 웹 사이트를 만드는 경우라면 이 정도의 지연시간은 크게 문제가 되지않지만, 상대적으로 신속한 반응을 요구하는 “웹앱"이라면 얘기가 달라진다.

해결책은 간단하다:
1. 손가락으로 무언가를 누르면(touchstart)
2. 웹킷의 기본 동작(300ms 지연)을 못하게 막고(preventDefault)
3. 움직임(touchmove) 없이
4. 손가락을 떼면(touchend)
5. 클릭(click)으로 간주한다.

touchstart/touchend을 mousedown/mouseup으로 바꿔놓고 보면 HTML5 이전에 drag & drop을 처리하기 위해서 사용하는 방식과 유사하다.

百聞不如一見! 코드를 살펴보자:
function NoClickDelay(el) {
this.element = el;
if( window.Touch ) this.element.addEventListener('touchstart', this, false);
}

NoClickDelay.prototype = {
handleEvent: function(e) {
switch(e.type) {
case 'touchstart': this.onTouchStart(e); break;
case 'touchmove': this.onTouchMove(e); break;
case 'touchend': this.onTouchEnd(e); break;
}
},

onTouchStart: function(e) {
e.preventDefault();
this.moved = false;

this.element.addEventListener('touchmove', this, false);
this.element.addEventListener('touchend', this, false);
},

onTouchMove: function(e) {
this.moved = true;
},

onTouchEnd: function(e) {
this.element.removeEventListener('touchmove', this, false);
this.element.removeEventListener('touchend', this, false);

if( !this.moved ) {
var theTarget = document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
if(theTarget.nodeType == 3) theTarget = theTarget.parentNode;

var theEvent = document.createEvent('MouseEvents');
theEvent.initEvent('click', true, true);
theTarget.dispatchEvent(theEvent);
}
}
};


百見不如一RUN! 코드를 돌려보자:
http://jsbin.com/exadi5


다시 말하지만, 위의 페이지는 터치기반의 모바일 웹킷, 즉 모바일 사파리나 모바일 크롬으로 봐야 효과가 있다.

일단 눈에 보이는 Slow Button과 Fast Button 각각을 평소대로 눌러보자. 클릭을 감지하는데 걸린 시간이 표시되는데, Fast 쪽이 조금 빠르긴 하지만 큰 차이는 없어 보인다.
이번에는 평소보다 좀 더 손끝에 감각을 모아서 “톡톡 두드린다는 느낌”으로 각 버튼을 눌러보자. Slow Button의 경우엔 아예 반응을 하지 않거나 확대(아이폰등에서는 더블탭이 자동 확대/축소)기능이 동작된다. Fast Button은 그런 동작을 하지 않는다.

이 글에서는 touchstart-touchmove-touchend 이벤트를 활용하여 버튼의 반응속도를 개선하는 방법을 알아보았다. 이 세가지 이벤트의 활용법을 잘 익혀두면 다양한 유형의 터치 입력을 처리하는데 많은 도움이 될 것이다.

참고 자료:
http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone
http://code.google.com/mobile/articles/fast_buttons.html
저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2010/11/18 14:50
크리에이티브 커먼즈 라이선스
Creative Commons License
얼마전에 쓴 "HTML5/CSS3/JavaScript로 아이폰 앱 만들기"에서 설명(응? 언제 설명했는데?) 반복적인 초기 작업을 더 쉽게 할 수 있도록 Xcode 프로젝트 템플릿을 만들어 보았다.

Dropbox에 올려둔 hellowebapp-ios-xcode_project_templates.tar.gz 를 받아서,
"~/Library/Application Support/Developer/Shared/Xcode/Project Templates"에 풀고,
Xcode에서 File 메뉴의 New Project를 선택하거나,
Xcode를 실행하고 "Create a new Xcode project"를 선택)하면,
프로젝트 템플릿을 선택하는 대화상자가 나오는데,
"User Templates" 아래에 "WebApp" 카테고리 안에 "HelloWebApp"을 선택하면,
지정한 이름으로 깔끔한 "웹 앱" 프로젝트가 만들어 진다.
(입맛대로 Device나 Simulator로 타겟을 바꾸고)
이제 그냥 "Build & Run" 하시면 되시겠다~


참고로, 지난 번 스크린캐스트 이후에, 웹 리소스(html, css, js, png...)들을 다른 소스와 분리해서 "www" 디렉토리 안에 몰아 넣도록 약간 수정된 버전이다.

안드로이드용 템플릿은 어떻게 만들까 고민 중... -_-; 이거 하자고 이클립스 플러그인을 만들 수도 없고...

저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2010/11/16 12:55
크리에이티브 커먼즈 라이선스
Creative Commons License
사무실에 앉아서 이짓꺼리(?) 하고 있다.

이런 쓰잘데기 없는 동영상을 굳이 만들어 올리는 이유는 "웹 앱"(WebApp; HTML5App)이 그렇게 거창한 것도 아니고, 어려운 것도 아니고, 멀리 있는 남의 나라 이야기도 아니라는 것을 보여주기 위해서다.
PhoneGap, Titanium, QuickConnect 같은 거창한(?) 제품을 동원하지 않더라도 JQueryMobile, Jo, Wink, Sencha Touch 같은 UI 툴킷과 HTML5 canvas 태그 그리고 HTML5 JS API들(WebStorage, WebSQLDatabase, WebWorker, ...), 그리고 W3C의 DAP(Geolocation, ...)를 사용하면 웬만한 앱은 만들 수 있다.

(저번에 XCode로 했던 짓이랑 비슷해서 이번에는 시간이 많이 안걸렸다능 -.-V)



동영상 간의 의존성을 제거(?!)하기 위해 html과 js를 직접 입력했지만, 저번에 아이폰 앱 만들때 썼던 파일을 그대로 써도 된다. 당연한 얘기~

마찬가지로, 예제 소스는 github에 올려두었다.

담(이건 정말 술 이름인데...)에는 좀 더 그럴싸한 앱을 만들어보자. 뭘 만들까? 흠...

저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2010/11/14 21:18
크리에이티브 커먼즈 라이선스
Creative Commons License
풍경 1. 아이폰이 국내에 출시된지 1년도 안됐는데... 아... 아이폰 없던 시절이 어땠는지 기억조차 가물가물... 먹고 살려니 아이폰 개발 공부는 해야겠는데, 망할 놈의 옵씨... 옵씨는 그렇다 치고, 코어 파운데이션, 코어 그래픽스, 코어 애니메이션, 뭔 코어가 이렇게 많냐? 핵분열도 아니고... OTL

풍경 2. 없는 살림에 거금 10만원 들여 아이폰 앱 개발자 등록해서 1년 동안 앱 3개 겨우 올렸는데... 안드로이드가 대세? 열라 안드로이드 공부해서 앱 좀 올려 볼려니... 안드로이드 마켓은 뭐고 티스토어는 뭐고 올레마켓은 또 뭐냐? 그까이꺼 대충~ 눈감고 넘어가려니... 블랙베리? 심비안? 팜프리? 윈폰7? 바다? OTL

풍경 3. 아래아한글 새 버전 나온 줄 알았던 넷스케이프와의 첫만남, 문자열과 한판 승부를 벌였던 CGI 시대, ASP, PHP, JSP... OOO 서버 페이지 시대, 유행따라 삼만리 AJAX 시대... 어느새 HTML만으로 어플리케이션을 만드는 시대??? 먹고살려니 안할 순 없고... OTL

풍경 4. 스마트폰(그게 뭔데? 먹는거냐?)용 앱을 만들긴 만들어야 겠는데.. 새로운 언어 배우기도 귀찮고, API는 낯설고, 당장 할 줄 아는 건 웹... 그래서 웹 기술만으로 앱을 만들 수 없을까... phonegap은 또 뭐고 titanium은 또 뭐고, WAC은 또 뭐냐? OTL

그래서 준비했습니다.

(재생 시간은 3분 남짓이지만 제작하는데는 30분 넘게 걸렸다능...ㅠㅠ)



동영상은 helloworld 수준이지만, 요기까지하고 나면 나머지는 하기 나름...
예제 소스는 github에 올려두었다.

조만간(그건 또 어디서 나온 술 이름이냐?) HTML5/CSS/JavaScript로 안드로이드 앱 만들기도....


저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2010/10/08 12:57
크리에이티브 커먼즈 라이선스
Creative Commons License

업무상 필요해서 작성한 글이지만,  혹시 도움이 될까 해서 올려봅니다. 블로깅 안한지 너무 오래되서 ㅎㅎ


홈페이지: http://joapp.com/

개발자: Dave Balmer(Palm WebOS 개발자, 전 야후 개발자)

요약: all-in-one 스타일의 경량 자바스크립트 라이브러리.


특징

  • UI 툴킷
    • CSS 기반 테마/SKIN 지원
  • 오픈소스
    • OpenBSD 라이센스
  • 크로스 플랫폼
    • Palm WebOS, Safari(iOS,Desktop,Dashboard), Chrome(Android,Desktop) 등 webkit 기반 브라우져만 지원.
  • 경량
    • 자바스크립트 41K(최소화된 버전) + UI CSS/리소스(176K)
  • PhoneGap 호환(?)
    • PhoneGap과 호환되지 않는 자바스크립트 라이브러리는 ”없음”.



주요 기능


UI


최근 모바일 단말 UI의 de-facto인 iOS의 UI을 염두에 둔 UI 툴킷.
하나의 화면(joScreen)은 상단의 헤더(joTitle, joToolbar)와 푸터(joFooter, joToolbar)로 구성.
화면과 화면 사이를 앞뒤(위아래)로 이동하는 네비게이션 레이아웃(joStackController, joStack).
기본적인 HTML 폼의 입력 필드에 대응하는 위젯들(joControl, ...), 페이지 내부 팝업(joPopup) 등의 필수적인 위젯 제공.
CSS를 통한 테마/스킨 지원.
캘린더, 챠트 등의 고급 위젯 부족.
  • joContainer
    • joCard
    • joFlexcol
    • joFlexrow
    • joFooter
    • joGroup
    • joPopup
    • joScreen
    • joScroller
    • joStack
    • joStackScroller
    • joTitle
    • joToolbar
  • joControl
    • joButton
    • joCheckBox
    • joExpando
    • joHTML
    • joInput
      • joDateTime
      • joPasswordInput
      • joTextarea
    • joLabel
    • joList
      • joMenu
      • joTabBar
      • joTable
    • joKnob
    • joSlider
  • joDivider
  • joShim

Data


HTML5의 WebSQLDatabase(Webkit 기반 브라우져에는 대부분 제공됨)를 통한 로컬(클라이언트측) 데이터베이스 접근 제공.
추후에 PhoneGap과 연계하여 로컬 파일을 통한 데이터 접근을 제공할 계획으로 보임(joFile, joFileDataSource)
원격(서버측) 데이터 접근 부재.
  • joDatabase
  • joDataSource
    • joFileDataSource (x)
    • joSQLiteDataSource
  • joFile (x)


Utility


기본적인(필수적인) 유틸리티 API 제공.
추후에 PhoneGap과 연계하여 모바일에 특화된 기능을 제공할 계획으로 보임.
  • jo, joCache, joScript
  • joEvent, joSubject, joGesture
  • joChain, joYield, joWait
  • joDOM, joJSON, joLocal, joString, joTime
  • joLog
  • joClipboard, joDevice, joFocus, joPreference, joUser


유사 제품과 비교


Jo Sencha Touch jQuery DojoToolkit
지원브라우져 Webkit All All All
IE ✭✭✭ ✭✭✭ ✭✭✭
FF ✭✭✭✭✭ ✭✭✭✭✭ ✭✭✭✭✭
Webkit(Safari,Chrome) ✭✭✭✭✭ ✭✭✭✭✭ ✭✭✭✭✭ ✭✭✭✭✭
모바일 최적화 ✭✭✭✭✭ ✭✭✭
데스크탑 지원 ✭✭✭✭✭ ✭✭✭✭✭ ✭✭✭✭✭
용량 ✭✭✭ ✭✭✭✭✭
UI 위젯 툴킷 ✭✭✭ ✭✭✭✭✭
EXT2 

jQuery UI 필요. jQueryMobile은 10월 중 알파 릴리즈 예정.
✭✭
dojox.mobile은 아직 unstable
UI 위젯 성능 ✭✭✭✭ ✭✭✭
i18n/l10n/a11y ✭✭✭ ✭✭✭✭✭
OOP ✭✭ ✭✭✭
DOM/CSS ✭✭ ✭✭ ✭✭✭✭✭ ✭✭✭
Database ✭✭ ✭✭✭✭ ✭✭✭ ✭✭✭✭✭
유틸리티 ✭✭✭ ✭✭✭✭✭ ✭✭✭
확장성 ✭✭✭✭✭ ✭✭✭
문서/예제 ✭✭✭ ✭✭✭✭✭ ✭✭✭
개발자 생태계 ✭✭✭ ✭✭✭✭✭ ✭✭✭



결론


비교적 적은 용량에 (모바일) 웹 앱 개발에 필요한 기본적인(필수적인) 기능을 거의 다 포함한 all-in-one 성격의 UI 라이브러리.

단순한 API 구조 덕분에 학습 / 사용이 용이하지만, 고급 기능들이 거의 없어서 jQuery등의 다른 라이브러리들과 혼용해야 함.

(이름과 달리) HTML5나 모바일에 최적화가 부족하고, 프레임워크가 아닌 단순 UI 툴킷 + 유틸리티 라이브러리.

1명의 개발자가 단독으로 개발했고, 비교적 최근(2010.6)에 시작해서 개정 릴리즈가 많지 않았기 때문에 소스 코드의 품질이 매우 높음.

HP가 Palm을 인수한 이후, WebOS의 Mojo를 개선(혹은 대체)하기 위한 여러가지 시도를 하는 것으로 보임.

직접적인 경쟁 상대인 Sencha가 상용/오픈소스로 모호한 라이센스 정책을 갖는데 반해, Jo는 OpenBSD 라이센스(BSD 라이센스와 어떤 차이가 있는지는 추가적인 확인이 필요)에 따름.

이후,  HP/Palm의 지원과 커뮤니티의 반응에 따라 주요 플레이어로 성장할 가능성은 있으나, 10월 중에 첫 릴리즈가 나올 예정인 jQueryMobile의 완성도에 따라서는 수많은 마이너 플레이어 중의 하나로 전락할 가능성이 더 높음.

저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2009/12/10 17:15
크리에이티브 커먼즈 라이선스
Creative Commons License
원래 발표 자료는 총 15장이 었는데, 예제 코드와 설명이 필요한 것은 이번으로 마무리 하려고 한다.

implicit type conversion

자바스크립트는 약한 타입(weak typing) 이므로, 묵시적인 형변환(implicit type conversion)이 빈번하게 이루어진다. 이로 인한 부작용을 간과하면 찾기 어려운 버그를 만들 수 있다.

간단한 예를 통해 알아보자:
function test(foo) {
  alert(typeof(foo));
  alert(foo);
  if (foo) { alert('foo'); }
  if (foo == null) { alert('foo == null'); }
  if (foo === null) { alert('foo === null'); }
}

이 함수를 여러가지 파라메터를 주면서 호출해보자.
test();
test(null);
test('hello');
test('');
test(true);
test(false);
test(1);
test(1/0);
test(0/0);

특이한 것 몇가지만 얘기하면:
  • underfined는 == null 이지만 === null 은 아니다.
  • ''는 false다! (C에서는 !=0 이면 모두 true라는 사실을 기억하라)
  • 1/0(불능)은 true지만, 0/0(부정)은 false다!

묵시적 형변환과 관련된 또 다른 예를 살펴보자:
function test(foo) {
  alert(typeof(foo));
  alert(foo);
  if (foo) { alert('foo'); }
  if (!foo) { alert('!foo'); }
  if (!!foo) { alert('!!foo'); }
}

파라메터가 명확한 불린 값이라면(true/false) 아무런 문제가 없지만, 그렇지 못하면 예상치 못한 상황에 직면하게 된다:
test(true);
test(false);
test('true');
test('false');

특이한 것은:
  • !!'false'는 false가 아니라 true다.

weak typing은 아주 편리한 언어적 특성이지만, 잘못쓰면 - 특히 strong typing(C, 자바 등의 대부분의 주류 언어)에 익숙한 개발자들에게 - 치명적인 독이 될 수 있다. underfined, null, NaN 그리고 ""(빈문자열) 간의 차이는 상당히 오묘하므로, 가장 확실한 방법은 확신이 없다면 명시적인 형변환을 수행하는 것이다.

nested block scope

function test() {
  var foo = -1;
  for (var foo = 0; foo < 10; foo++) { … }
  alert(foo);
}

위의 코드에서 두번째 var 선언문은 아무 효과가 없다. 따라서, -1이 아니라 10이 출력된다. 별것 아닌것 처럼 보이지만, 문제가 되면 굉장히 찾기 어려운 버그다. jslint를 사용하면 경고를 해주는 데, 가장 확실한 방법은 모든 변수 선언을 함수 앞에 모아두는 것이다(예전 C 스타일).
 
function overloading

function test(foo) {
  alert('one arg');
}
function test(foo, bar) {
  alert('two args');
}
function test() {
  for (var i = 0; i < arguments.length; i++) {
    alert(arguments[i]);
  }
}

위의 코드에서 앞에 두개의 함수 정의는 무시되고, 마지막의 세번째 함수 정의만 유효하다. 자바스크립트에서는 arguments를 사용하여 가변 파라메터를 처리할 수 있다. 그러나, 더 좋은 방법은 이름있는 파라메터를 사용하는 것이다. 즉, 객체 하나에 파라메터의 이름과 값을 함께 전달 하는 것인데, 요즘 많이 쓰이는 대부분의 자바스크립트 라이브러리들이 모두 이 방식을 선호한다.

"string" is not array-of-chars

var str = "hello";
alert(str.charAt(2));
alert(str[2]);

위의 코드에서 앞의 alert은 출력되지만, 뒤의 alert은 에러다. 잘된다고? IE에서는 해보시길...
자바 개발자들에겐 익숙할텐데, C/C++ 개발자들은 좀 귀찮을 듯... ^^;

비슷한 예로, NodeList(예: document.getElementsByName() 등의 리턴 형식)도 배열이 아니다.

missing "radix" for  parseInt()

parseInt('1234');
parseInt('01234');
parseInt('0x1234');
parseInt('1234', 10); 
parseInt('1234', 8);
parseInt('1234', 16);

뭐가 이상하냐고? 자바에서 똑같은 짓을 해보자. -.-;;;; 자바에선 Integer.parseInt()에 radix를 지정하지 않으면 10을 지정한 것으로 처리하지만, 자바스크립트에선 알아서 하라는 뜻으로 해석한다.

var sum = parseInt(num1.value) + parseInt(num2.value);
alert(sum);

위의 코드는 의도했던 안했던, 8진수와 16진수 계산기 기능도 갖고 있다. ^^; 이런 사소한 문제가 찾아내기 힘든 버그를 만든다. jslint를 사용하면 경고를 해주는데, 가장 확실한 방법은 parseInt()를 호출할 때 무조건 두번째 파라메터(radix)를 지정하는 것이다. 

이것으로 JavaScript Common Mistakes 시리즈도 끝~
그 시작은 창대하였으나 끝은 미미하리라...=3=3=333

아.. 쪽팔려...

저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2009/12/09 19:55
크리에이티브 커먼즈 라이선스
Creative Commons License
자바스크립트로 심각한 코딩을 하기 시작하던 초기에 했던 삽질이다. 그 전까진 아예 "this"라는 키워드를 쓸 일 자체가 없었다.

가장 간단한 예제를 보자:
function test(name, button) {
this.name = name;
button.onclick = function(event) {
alert('hello, ' + this.name);
};
}
문제는, 이 코드에서 아래에 있는(4줄) "this"가 위에 있는(줄2) 그 "this"가 아니라는 건데...

그럼 어떻게 해야하나? 여러가지 방법이 있겠지만, 가장 일반 적인 방법은 이렇게 하는 거다:
function test(name, button) {
this.name = name;
var self = this;
button.onclick = function(event) {
alert('hello, ' + self.name);
};
}
변수 이름은 self가 아니어도 상관없지만, 일반적으로 self, me, this_, _this 등을 많이 쓴다.

이론에 근거한 체계적인 설명은 크록포드옹께서 쓰신 JavaScript: The Good Parts 를 정독하시고...

이것만 기억하자:
자바스크립트의 this는 함수가 "선언된 위치"가 아니라, 함수가 "호출 문맥(invocation context)호출된 위치"에 따라 결정된다.

위의 코드에서, 사용자가 버튼을 누르면 button.onclick에 연결된 콜백 함수를 호출하는데, 그 시점의 this는 함수가 선언된 위치인 test 객체가 아니라, 콜백 함수를 호출하는 "버튼"(DOM 노드)이다. 그래서 엉뚱한 값(버튼 태그의 name 속성 값)이 출력되는 것이다.

더 헷갈리다고...? Orz

대부분의 this와 관련된 문제는 위에서 설명한 꼼수와 자바스크립트의 Function.prototype.apply()Function.prorotype.call() 를 통해 해결할 수 있다. prototype.js 의 Function.bind() 와 dojo 의 dojo.hitch() 도 결국은 같은 일을 한다(그래서 jQuery에는 없다).

흠냐... 아직 많이 남았는데... 벌써... 귀차니즘 발동... -,.-;;;

저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2009/12/08 17:21
크리에이티브 커먼즈 라이선스
Creative Commons License
내 스스로와의 약속(하루에 한개씩 블로그를 쓰겠다는)을 지키면서, 또 다른 약속(지난 번 dW Live!의 페차쿠차 발표에 대한 보충 수업을 하겠다는)을 지키기 위해 여러 번에 나눠 쓰기로 했다 :p

천덕꾸러기 취급 받던 자바스크립트가 다시 각광을 받게된 것은 웹2.0 열풍에 실려 날아온 AJAX 때문이다. AJAX의 A가 Asynchronous라는 것은 자바스크립트 개발자라면 누구나 아는 사실임에 종종 이를 망각하는 경우가 있다.

가장 쉬운 예를 보자:
function get_result() {
  var result1, result2;
  $.ajax({ ..., success: function(data) { result1 = data; });
  $.ajax({ ..., success: function(data) { result2 = data; });
  return result1 + result2;
}

이게 뭐가 문제냐~고 하시면 대략 난감~ 정말 곤란~하시다.

설마 저렇게야 하겠어라고 생각하신다면, 좀 더 그럴듯한 예를 들어보자:
function get_image_size(image_src) {
  var img = new Image();
  img.src = image_src;
  return { w: img.width, h: img.height; };
}

이미지를 자바스크립트로 동적으로 이미지를 로딩하고 크기를 구해서 어떤 짓을 하려나 본데...
뭐가 문제냐고? 없으면 말고~=3=3=33

좀 더 고급스런(?) 예제로 마무리하자:
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1");
$(document).ready(function() { ... });
</script>

좀 더 나은(정답은 없다) 방법은... 스스로 생각해 보시길...=3=3=33

i'll be back~

i'll be back~



저작자 표시 동일 조건 변경 허락
Posted by iolo
hacking/web2009/08/24 14:35
크리에이티브 커먼즈 라이선스
Creative Commons License
제목 그대로 심심풀이~

플래시나 canvas같은 잡다한거(?) 안쓰고 HTML/CSS/자바스크립트만 사용해서 만들었다.
달랑 게임만 만들기엔 심심하기도 하고... 딱히 올려놓을 곳도 없고 해서... 구글 앱엔진을 이용해서 점수를 기록하는 모듈도 만들었다.


돌아가는 모습은 http://iolo.appspot.com/ 에서 볼 수 있고~
소스 코드는 http://code.google.com/p/iolothebard/ 에서 볼 수 있다~

심심풀이 코딩이 다 그렇듯...
대충 돌아가기 시작하니까 재미가 없어져서... 얼렁뚱땅 마무리했다.
혹시 관심있는 분이라면~ 이거저것 고쳐보면 재미있을라나?

Posted by iolo
hacking/web2009/01/07 16:31
크리에이티브 커먼즈 라이선스
Creative Commons License

Dojo Objective Harness라니... 참 이름도 잘 짓는다. 원래는 그냥 Dojo Helper의 약자였는데... -.-;

아무튼 자바스크립트 단위테스트로 고민하고 있는 분들이라면 한번 쯤 읽어봐도 좋을 튜토리얼이다.
dojo와 무관하게 함수들을 동기/비동기로 테스트할 수 있다.
어느 정도 자동화도 가능하지만, 이 경우엔 rhino를 사용하기 때문에 실제 브라우져에서와 다른 결과가 나올 수 있으므로 그다지 유용하다고 할 수 없다. 대부분의 경우엔 수시로 브라우져를 통해서 테스트를 한번씩 돌리는 것이 더 확실하다.

간단한 대체품으로는 JsUnit이 있긴 하지만... 그닥 -.-;
dojo는 죽어도 싫다거나, 더욱 강력한 녀석을 원한다면 Selenium을 검토해보는 것이 좋을 듯 ~.~

Posted by iolo
hacking/web2008/10/24 17:08
크리에이티브 커먼즈 라이선스
Creative Commons License
한국 developerWorks에 기고한 번역문

원문: Develop AJAX applications like the pros, Part 3: Use DWR, Java, and the Dojo Toolkit to integrate Java and JavaScript
번역: 전문가다운 Ajax 애플리케이션 개발, Part 3: DWR, 자바, Dojo 툴킷을 사용하여 자바와 자바스크립트 통합하기

전형적인 디벨로퍼웍스 스타일의 제목... 원츄! -.-)b~

제목과는 달리 dojo 얘기는 없다.
대신, 자바 개발자들을 위한 거져 먹는 Ajax! DWR이 있다.
정말~ 쉽고! 정말~ 편하다!
장담하건데... 기존에 자바로 구축된 웹 사이트에 간단한 Ajax를 추가하는 거라면 이 보다 더 좋은 솔루션은 없다.

百問而不如一見~

Posted by iolo
hacking/web2008/10/08 00:39
크리에이티브 커먼즈 라이선스
Creative Commons License
아싸~ 아기다리고기다러던~~ (이런 개그하지 말랬지~ +-.-)==@ (*..*) 퍼퍽!)

*경* Dojo Toolkit 1.2 정식 버전 릴리즈~~ *축*

Alex Russell의 뒤를 이어 Pete Higgins가 메인테이너를 맡은 뒤 첫 릴리즈다.
아무튼, 뭐가 달라졌나 볼까나~.~

새로운 데이터스토어들
  • dojox.data.JsonRestStore
  • dojox.data.CouchDBRestStore
  • dojox.data.GoogleFeedStor
  • dojox.data.GoogleSearchStore
  • dojox.data.PersevereStore - Perservere... 쓰는 사람이 있구나... -.-;
  • dojox.data.S3Store
JsonRestStore는 어디에나 써먹을 수 있을 정도고, 나머지도 나름대로 유용할 듯.

dojox.analytics.Urchin
구글 애널리틱스 스크립트 지연 로딩하는 모듈.
몇 바이트 되지도 않는 자바스크립트 때문에 가끔 먹통되는 상황을 경험해 본 개발자라면 유용하겠다.
내가 다니는 회사에서는 loginside라는 솔루션을 쓰는데, 이 녀석 조금 고치면 될 듯^^;

audio/video/object/embed 지원 모듈들
  • dojox.av.FLVideo
  • dojox.av.widget.Player
  • dojox.embed
  • dojox.embed.Flash
  • dojox.embed.Flash.proxy
  • dojox.embed.Quicktime
  • dojox.embed.Object
뭐~ 보시는 대로... dijit 위젯으로 만들어져서 일관성도 있고, 쓰기도 편해졌다.

엽기적인 크로스도메인 Ajax. 보면... 왜 엽기적이라고 하는 지 알 수 있다. -.-;
세삼 확인하는 사실...
세상은 넓고 꼴통은 많다...

dojox.io.xhrPlugins
dojo.xhr을 여러가지 방법으로 확장할 수 있는 방법을 제공한다.
예를 들면 크로스도메인일 경우엔만  IE8의 XDomainRequest나 서버측 프록시를 사용한다거나... Loading 메시지를 표시한다거나...
개인적으론, 1.2에 추가된 최고의 기능이 아닐까 한다.

dojo 0.x 시절에도 있었던 AOP 기능을 깔끔하게 새로 만들었다. 이런 거 보면 dojo가 너무 많이 앞서 갔다. -.-;

dojox.lang.observable
객체의 속성을 읽거나, 쓰거나, 메소드를 호출하는 것을 (비동기로) 감시하는 멋진 기능인데... IE에서 문제가 쪼금~ 있다는...-.-;

보안 관련 모듈들
  • dojox.secure.capability: 자바스크립트 코드를 검증한다. 그래도 eval은 여전히 evil~
  • dojox.secure.DOM: DOM 노드의 접근을 제한한다. 쉬운 말로... 자바스크립트로 DOM API의 래퍼를 다 만들었다는... -.-;;
  • dojox.secure.sandbox: 위의 모듈들을 사용하여 XHR을 통해 다른 도메인에서 로드된 HTML, JSON, 자바스크립트들의 접근을 제한한다. 옥상옥이라는게 이런건가...-.-;;;

덤으로...(알만한 사람들은 이미 알고 있겠지만)
기존에 AOL에서 제공하던 CDN 외에 구글에서 제공하는 CDN을 통해서 다운로드/설치 없이 바로 쓸 수 있다.

더 자세한 얘기는 공식 릴리즈 노트에~~

덧. 1.2 릴리즈 소식을 듣고 다운받으러 갔다가 무심결에 맨 위에 있는 링크를 눌렀더니... dojo.js -.-;;;;
prototypejquery 덕분에(?) 크기에 대한 압박이 심했나 보다. 아무튼 prototype.js나 jquery.js 대용이라면 dojo.js 파일 하나면 충분하고... dijit을 포함한 dojo 모든 것을 맛보려면 역시 풀버전~ ^^; 그 전에 눈요기가 필요하다면 Dojo Feature Explorer~ =3=333


Posted by iolo
hacking/web2008/10/05 23:14
크리에이티브 커먼즈 라이선스
Creative Commons License
한국 developerWorks에 기고한 번역문

원문: Ajax overhaul, Part 4: Retrofit existing sites with jQuery and Ajax forms
번역: Ajax로 사이트 전면 개편, Part 4: 기존 사이트를 jQuery와 Ajax forms를 사용하여 개선하기

열화와같은 독자들의 성원에 힘입어 연장 방영 중인 Ajax 오버홀 시리즈~

4부에서는 앞에서 한번 써 먹었던 jQuery Tabs UIjQuery Forms를 사용하여, 예제 애플리케이션인 Customize Me Now의 구매 과정을 마법사 스타일의 UI로 개선한다.

百問而不如一見~

Posted by iolo
hacking/web2008/09/23 21:14
크리에이티브 커먼즈 라이선스
Creative Commons License
한국 developerWorks에 기고한 번역문

원문: Ajax overhaul, Part 3: Retrofit existing sites with jQuery, Ajax tabs, and photo carousels
번역: Ajax로 사이트 전면 개편, Part 3: jQuery, Ajax 탭, 회전식 슬라이드쇼로 기존 사이트 개선하기

Ajax 오버홀, Part 1: Ajax와 jQuery로 기존 사이트 개선하기Ajax 오버홀, Part 2: jQuery, Ajax, 툴팁, 라이트박스로 기존 사이트 개선하기로 마무리된 줄 알았던 오버홀 시리즈...
열화와같은 독자들의 성원에 힘입어 연장~~?!

하긴.. 그렇게 끝나면 열라 허무했을 거다.
지금 4부까지 번역했는데... 분위기로 봐선 5부도 조만간 나올 듯...

3부에서는 jCarousel 플러그인을 이용한 회전식 슬라이드쇼와 jQuery Tabs UI 플러그인을 이용해서 탭 UI를 만든다.
百問而不如一見:


확실히 jQuery 가 좋은 것 같은데... 하지만...
나는 dojo 빠~=3=3=333

덧1. 이번 글을 번역할 때 애먹은 단어는 carousel이다. 회전 목마... -.-;;;; 저게 뭘로 봐서 회전 목마냐고...
궁여지책으로 회전식 슬라이드쇼라고 번역했지만, 찝찝하다.
편집자께서 알아서 고쳐주시겠지 했는데... 그대로다.
뾰족한 대안이 없었나 보다. 좋은 단어 추천 요망~.~/

덧2. 연재 1~2부를 번역할 때 overhaul을 어떻게 번역할 지를 고민하다가, 그냥 한글로 "오버홀"이라고 해다.
이번에는 편집자께서 제안해주신 "분해 수리"로 바꿨는데, 오늘 올라온 기사에는 "전면 개편"이라고 바뀌었다.
흠... 그런데... 뭔가... 좀...
이 연재에서 거듭 강조하는 핵심 중의 하나는 "전면" 개편이 아니라 "점진적" 개편이라는...
웃거나 말거나...=3=3=33

Posted by iolo
hacking/web2008/08/20 23:06
크리에이티브 커먼즈 라이선스
Creative Commons License
여름 휴가도 있고... 밥먹고 사는 일도 있고 해서... 한참 쉬었으니 다시 시작해보자.

dojo의 객체 시스템의 핵심은 dojo.declare다:
  • dojo.declare(className, superClass, { members... }) : 주어진 이름을 가진 클래스를 정의한다. 클래스 이름은 문자열로, 수퍼클래스는 클래스 객체로 지정해야 한다. 수퍼클래스가 없으면 null 또는 [ ] (빈 배열)을 지정하면 된다. 하나 이상의 수퍼클래스(정확히는 하나의 수퍼클래스와 여러 개의 믹스인을 배열로 지정할 수도 있다.
먼저, 단순한 클래스를 정의하는 예를 보면:
dojo.declare('Point', null, {
    x: 0,
    y: 0,
    constructor: function(x, y) {
        this.x = x || 0;
        this.y = y || 0;
    },
    moveTo: function(x, y) {
      this.x = x;
      this.y = y;
   },
    equals: function(point) {
      return (this.x == point.x) && (this.y == point.y);
    }
});

위의 예는 Point라는 이름의 클래스를 정의한다. 이 클래스는 수퍼클래스가 없으며, 하나의 생성자(constructor)와 x, y 두 개의 속성(멤버 변수)을 가지며, moveTo, equals 세 개의 메소드(멤버함수)를 가진다.
키워드는 declare(선언)이지만, 실제로 하는 일은 선언이 아니라 정의(define)다. 오히려 dojo.provide가 선언에 가깝다. 이 글의 주제에서 벗어나는 얘기니 궁금하면 구글신께 물어보시라... 나중에 시간나면 따로 쓰기로 하자~

이 클래스를 사용하는 예를 보면:
var p1 = new Point(1, 2);
var p2 = new Point();
p2.moveTo(3, 4);
alert(p1.equals(p2)); // false

보다시피 자바 등의 다른 언어와 별 차이가 없다.

계속해서, 상속의 예를 보면:
dojo.declare('Rect', [ Point ], {
    w: 0,
    h: 0,
    constuctor: function(x, y, w, h) {
       this.w = w || 0;
       this.h = h || 0;
    },
    getRight: function() {
      return x + w;
    },
    getBottom: function() {
      return y + h;
    },
    resize: function(w, h) {
      this.w = w;
      this.h = h;
    },
    equals: function(rect) {
      return this.inherited(arguments) && (this.w == w) && (this.h == h);
    }
});


위의 예는 Rect라는 이름의 클래스를 정의한다. 이 클래스는 Point를 상속받으며(x, y 두 개의 속성과 moveTo, equals 두 개의 메소드), 추가로 w, h 두 개의 속성과 getRight, getBottom, resize 세개의 메소드를 정의하며, equals를 오버라이딩(재정의)하고 있다.
equals에서 this.inherited(arguments)라는 생소한 구문이 보이는데 부모클래스에서 정의한 메소드를 호출하는 것이다. 자바로치면 super(rect)와 비슷하다고 보면 되겠다.
생성자에서 super를 호출하지 않는다는 점도 주의해야한다. 아무말 안해도 무조건 super를 호출한다. 자바스크립트는 함수 오버로딩(중복정의)을 지원하지 않기 때문에 생성자를 하나밖에 가질 수 없다.

객체 관련 유틸리티 함수들이 여러가지 있지만, 개인적으로 한 번이라도 써 본적이 있는 녀석들만 간단히 알아보면:
  • dojo.delegate(obj, { members...}) : 주어진 객체를 상속받은 객체를 만든다. dojo.declare와 달리, 클래스가 아니라 인스턴스 객체를 만든다. 간단하게 몇 가지 속성이나 메소드만 재정의한 객체를 만들때 편리하다.
  • dojo.clone(obj) : 주어진 객체의 deep-copy 객체를 만든다.
dojo는 하나 이상의 클래스를 하나의 .js 파일에 넣어두고, 이를 동적으로 로딩하는 기능을 제공하는데, dijit 설명할 때 자세히 알아보기로 하고... 여기서는 dojo 관련 소스들을 보다가 자주 보게될 함수 몇가지만 알아보자:
  • dojo.require(className) :  현재 모듈(나중에 설명한다)에서 주어진 이름의 클래스를 참조(사용)한다. 자바의 import와 비슷하지만, 자바와 달리 와일드카드(*)를 사용할 수 없다(dojo 0.4.x 쓰시던 분들도 주의!). 일반적으로 dojo.require('dijit.form.TextBox')라고 하면 dojo디렉토리/dijit/form/TextBox.js를 로딩한다고 이해해도 무방하다.
  • dojo.provide(className) : 주어진 이름의 클래스를 선언한다. 즉, 현재 모듈(나중에 설명한다)에서 주어진 이름의 클래스를 정의할 것임을 미리 알린다. 실제로는 빈 객체를 정의하기 때문에 네임스페이스 선언을 위해서 사용한다.
위의 두 함수는 dojo custom build에서도 매우 중요한 역할은 한다.

오늘은 여기까지~

다음에는 아기다리고기다리던 dijit(dojo widget)이다.

덧. 자바스크립트로 진지한 코딩을 해 본 개발자라면 IE의 trailing comma error의 공포를 알고 있을 것이다. dojo.delcare도 조심해서 쓰지 않으면 좌절을 맛보게 된다. 조만간 동의하실 것이라개인적으로 즐겨쓰는 방법은:
  1. 무조건! jslint로 검사한다. 예전에 썼던 웹 프로젝트에서 jslint로 자바스크립트 검증하기: maven 또는 ant 를 참조하시라~
  2. 무조건! 각 멤버 변수/함수를 쉼표로 끝내고, 불필요한 comma를 넣는 실수를 방지하기 위해 더미로 속성을 하나 더 넣는다. 예를 들면:
dojo.declare('Circle', [ Point ], {
    attr1: 'test',
    attr2: null,
    func1: function() {
        ...
    },
    func2: function() {
        ....
    },
    _dummy: null
});


Posted by iolo
hacking/web2008/08/10 17:13
크리에이티브 커먼즈 라이선스
Creative Commons License
자바스크립트로 코딩 좀 했다는 분들도 IE(참고자료)와 불여우, 그리고 W3C의 표준 DOM 이벤트 모델간의 차이에 대해서 제대로 이해하기보다는 까이꺼~ 대충~ 통밥으로~ 처리하는 경우를 많이 본다. 누가 좋으냐 나쁘냐는 논쟁은 끝이 없으니... 넘어가기로 하고... 골치아픈 브라우져간의 차이점을 신경쓰지 않고 개발할 수 있는 dojo의 이벤트 시스템을 알아보자.
  • dojo.connect(이벤트객체, 이벤트이름, 이벤트핸들러함수) : 지정한 객체에서 지정한 이름의 이벤트가 발생하면 이벤트 핸들러 함수를 호출하도록 "연결"한다. 핸들을 리턴한다.
  • dojo.disconnect(핸들) : dojo.connect()함수의 리턴값으로 받은 핸들을 사용하여 이벤트와 이벤트 핸들러 함수의 연결을 끊는다.
뭔 얘긴지 더 헷갈린다. 간다한 예제를 보자:
<html>
<head>
<script type="text/javascript" djConfig="isDebug:true" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>
<script type="text/javascript">
</script>
</head>
<body>
<button id="helloBtn">Click Me</button>
<script type="text/javascript">
var helloBtn_onclick = function(evt) {
    alert('hello, world!');
    if (helloBtn_onclick_handler) {
       dojo.disconnect(helloBtn_onclick_handler);
       helloBtn_onclick_handler = null;
    }
};
var helloBtn = dojo.byId('helloBtn');
var helloBtn_onclick_handler = dojo.connect(helloBtn, 'onclick', helloBtn_onclick);
</script>
</body>
</html>

보시다시피 단순하다.

기존 방식대로 하면:
helloBtn_onclick = function(evt) {
    alert('hello, world!');
    helloBtn.onclick = null;
};
var helloBtn = document.getElementById('helloBtn');
helloBtn.onclick = helloBtn_onclick;

어랏?! 더 단순하자나! 그러나 이 코드가 항상 동작하는 것이 아니다라는 점이 문제다. 기존의 방식에 익숙하다면 지금 당장 바꿀 필요는 없다. dojo.connect가 있다는 점만 기억해두면 머지않아 필요할때가 올 것이다. 하나 이상의 이벤트 핸들러를 연결해야할 때, 이벤트 핸들러에서 이벤트의 전달을 중단해야 할 때, 또는 기본 동작(폼 submit같은)을 막고 싶을 때... 등등...
dijit(dojo의 위젯 시스템)을 쓴다면 별도로 disconnect를 해줄 필요가 없지만, 그 외의 경우에는 꼼꼼하게 disconnect해주는 것이 좋다. DOM 노드를 제거할때 dojo._destroyElement()를 사용하면 자동으로 연관된 이벤트 핸들러들을 disconnect 해주므로 편리하게 쓸 수 있다.

script태그가 body태그 끄트머리에 들어가있는 것이 이상하다고 생각한 분 계신가? 그렇다. 일부러 그렇게 한거다. 저렇게 안하면 브라우져와 주변 상황에 따라(!) 예상치 못한 결과를 만나게 된다. 그래서 dojo에서 이런 방법을 제공한다:
  • dojo.addOnLoad(핸들러함수) : 페이지를 열고 난 직후에 호출될 핸들러 함수를 추가한다.
  • dojo.addOnUnload(핸들러함수) : 페이지를 닫기 직전에 호출될 핸들러 함수를 추가한다.
백문이불여일견~
<html>
<head>
<script type="text/javascript" djConfig="isDebug:true" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>
<script type="text/javascript">
var helloBtn_onclick = function(evt) {
    alert('hello, world!');
};
var byeBtn_onclick = function(evt) {
    alert('bye~ world!');
    location.href = 'http://google.com/';
};
var handlers = [];
var init = function() {
    handlers.push(dojo.connect(dojo.byId('helloBtn'), 'onclick', helloBtn_onclick));
    handlers.push(dojo.connect(dojo.byId('byeBtn'), 'onclick', byeBtn_onclick));
};
var destroy = function() {
  dojo.forEach(handlers).disconnect();
}
dojo.addOnLoad(init);
dojo.addOnUnload(destroy);
</script>
</head>
<body>
<button id="helloBtn">Click Me</button>
<button id="byeBtn">Bye~</button>
</body>
</html>

예제가 좀 길어졌지만, 기존에 자바스크립질에 익숙한 분들은 dojo.addOnLoad/Unload가 body의 onload/onunload핸들러와 크게 다르지 않다는 것을 알아챘을 것이다. 즉, <body onload="init()" onunload="destroy()"> 이라고 하면 된다는 얘기~ 그런데 왜 저렇게 복잡하게 하느냐고? 예전에도 한번 포스팅한 적이 있는데... onload의 타이밍이 미묘해서 브라우져마다 조금씩 다르다.
좀 다른 얘기지만, 위의 예제 코드에서 init()/destroy()에서 사용된 배열에 이벤트 핸들들을 보관해두고 일괄 해제하는 패턴은 자주 사용되므로 익해두면 편하다.

보너스로 한가지 더:
  • dojo.stopEvent(이벤트객체) : 이벤트의 전파와 기본 동작을 모두 차단한다.
예를 들면:
<form id="loginForm" action="login.do" method="post">
    <input type="text" id="usernameText" name="username" value="" />
    <input type="password" id="passwordText" name="password" value="" />
    <button type="submit">Login</button>
</form>
<script>
dojo.connect(dojo.byId('loginForm'), 'onsubmit', function(evt) {
    if (!dojo.byId('usernameText').value || !dojo.byId('passwordText').value) {
      dojo.stopEvent(evt);
    }
});
</script>

자바스크립트에 익숙한 분들은 return false; 이런 짓(!)을 하시는데... 이거 생각처럼 잘 안된다. 이 기회에 링크한 문서들을 참고해서 왜 되고 또 왜 안되는지 좀 더 파 보시는 것도 괜찮을 듯...

다소 뜬금없지만, 이벤트 시스템의 일부이기도 하고, 유용한 녀석들이니 언급은 하고 넘어가야 할 것 같다:
  • dojo.subscribe(토픽이름, 토픽핸들러함수) : 지정한 토픽이 발생하면 호출할 핸들러함수를 추가한다.
  • dojo.publish(토픽이름, 파라메터배열) : 지정한 토픽을 발생시킨다. 그러면, 위의 dojo.subscribe()를 통해 등록한 핸들러 함수들이 모두 호출된다.
AJAX의 특성상 비동기 동작이 많고, 이를 처리하기위해서 코드가 꼬이고, 이렇게 꼬인 코드를 풀기 위해 전역변수를 많이 쓰게된다. dojo.publish/subscribe()를 사용하면 이러한 상황을 많이 줄일 수 있다. C언어를 오랜동안 쓰신 분이라면 setjmp/longjmp와 비슷하다고 생각할 수 있겠다. 제대로된 예제를 만들려면 꽤 긴 코드가 필요하니, 나중에 따로 설명하기로 하자.

다음은 dojo의 객체 시스템에 대해서 알아보기로 하고...
오늘은... 이만...
사용자 삽입 이미지
정말... 덥다...

Posted by iolo
hacking/web2008/08/06 14:08
크리에이티브 커먼즈 라이선스
Creative Commons License
한국 developerWorks에 기고한 번역문

원문: Develop Ajax applications like the pros, Part 1: Using the Prototype JavaScript library and script.aculo.us
번역: 전문가다운 Ajax 응용 프로그램 개발, Part 1: Prototype 자바스크립트 라이브러리와 script.aculo.us 사용하기

developerWorks 특유의 장황한 제목이 인상적이다.
장황한 제목은 무시하고... 내 맘대로 제목을 붙여본다면...
프로토타입스크립타큘러스로 배우는 AJAX 프로그래밍 입문.



Posted by iolo
hacking/web2008/08/02 21:28
크리에이티브 커먼즈 라이선스
Creative Commons License
이번에 알아볼 내용은 애니메이션/효과를 위한 기능이다.

기본 효과
간단한 효과들이지만 dojo base에 포함되어 있어서 dojo.js 파일 하나만 있으면 편하게 쓸 수 있다.
  • dojo.fadeIn(args) : 지정한 노드를 서서히 불투명하게 만든다. args는 여러가지 파라메터를 묶은 해시다. dojo에서는 이런 식의 파라메터를 즐겨쓴다.
  • dojo.fadeOut(args) : 지정한 노드를 서서히 투명하게 만든다.
  • dojo.animateProperty(args) : 지정한 노드의 (CSS) 속성을 연속적으로 변화시킨다. 이 함수만 활용하면 대부분의 효과를 만들 수 있다.
간단한 예를 들어 보면:

dojo.fadeOut(
    node: 'title',
   duration: 1000,
   delay: 250
  }).play();

250ms를 기다린 후, 1000ms(1초)동안 id가 title인 노드를 천천히 표시한다(불투명). fadeOut대신 fadeIn을 사용하면 숨긴다(투명).

dojo.animateProperty({
    node: 'title',
    properties: {
        width:{ start:10, end:500, unit:'px' },
        opacity: { start:0, end:1 },
        backgroundColor: { start: '#ff0000', end: '#00ff00' }.
        fontSize: { start:10, end:20, unit:'pt'},
   },
    duration:500
});

500ms(0.5초) 동안 domNode의 너비를 10px에서 500px로, 투명에서 불투명으로,  배경색을 빨강에서 초록으로, 글꼴 크기를 10pt에서 20pt로... 부드럽게~ 바꾼다. 즉, 위의 dojo.fadeIn/fadeOut()은 dojo.animateProperty()로 쉽게 구현할 수 있다.

좀 더 복잡한(그래봐야 길어 보일 뿐~) 예를 만들어보자:
<html>
<head>
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>
<style type="text/css">
#welcome { display:none; position:absolute; top:50px; left:50px; width:300px; height:200px; border:2px solid #cc0000; background-color:#00ff00; color:#0000ff; }
</style>
<script type="text/javascript">
var showWelcome = function() {
  // fadeIn이 효과가 있으려면 먼저 투명하게 만들어둬야 한다.
  dojo.style('welcome', { opacity: '0', display: 'block' });
  dojo.fadeIn({
    node: 'welcome',
    duration: 1000,
    delay: 1000
  }).play();
};

var flyWelcome = function() {
  var bodyBox = dojo.contentBox(dojo.body());
  var welcomeBox = dojo.contentBox('welcome');
  var goArgs = {
    node: 'welcome',
    properties: {
      left: bodyBox.w - welcomeBox.w,
      top: bodyBox.h - welcomeBox.h
    },
    duration: dojo.byId('flyTime').value * 1000, // 밀리초
  };
  var goAnim = dojo.animateProperty(goArgs);
  goAnim.play();
};

var hideWelcome = function() {
  dojo.fadeOut({
    node: 'welcome',
    duration: 1000,
    delay: 100,
    onEnd: function() { dojo.style('welcome', 'display', 'none'); }
  }).play();
  // 애니메이션은 비동기로 일어난다.
  // 여기에 dojo.style('welcome', 'display', 'none');를 넣으면
  // 애니메이션을 시작하자마자 바로 사라져버리므로(display:none),
  // 스르륵 사라지는(투명도를 조절하는) 효과를 볼 수 없게된다.
};

dojo.addOnLoad(showWelcome);
</script>
</head>
<body>
<h1>Hello, World!</h1>
<p>Blah Blah...</p>

<div id="welcome">
<h1>Welcome!</h1>
<p>Blah Blah...</p>
<p>
<button onclick="flyWelcome()">Fly me to the moon</button>
during <input type="text" id="flyTime" value="1" size="5" /> seconds.
</p>
<button onclick="hideWelcome()">Let it be</button>
</div>

</body>
</html>

페이지가 로딩되면 잠시 뒤에 Welcome 창(?)이 스르륵~ 나타난다. 여기서 Let it be를 누르면 창이 스르륵~ 사라지고, Fly me to the moon을 누르면 지정한 시간동안 창이 아래쪽 구석으로 날아간다.
예제 자체는 별거 없지만, 중간에 코멘트 중에 중요한 내용이 있다. 애니메이션은 항상 비동기로 진행된다는 사실을 명심하자. 동기를 맞추려면 그래서 onBegin, onEnd 등의 이벤트를 이용해야 한다.

고급 효과(dojo.fx 패키지)
dojo base에 효과를 자꾸 추가하면 dojo.js 파일의 크기가 너무 커지므로, dojo.fx 라는 별도의 패키지를 만들었다. 따라서 아래의 효과들을 사용하기 전에 dojo.require('dojo.fx');를 실행해야 한다.
  • dojo.fx.chain([애니메이션객체들...]) : 여러 개의 효과을 순서대로 실행하는 복합 효과.
  • dojo.fx.combine([애니메이션객체들...]) : 여러 개의 애니메이션을 동시에 실행하는 복합 효과.
  • dojo.fx.slideTo({ node: 노드, top: 세로좌표, left: 가로좌표 }) : 노드를 지정한 좌표로 이동하는 효과.
  • dojo.fx.wipeIn({ node: 노드 }) : 노드의 높이를 점점 크게하면서 나타나는 효과.
  • dojo.fx.wipeOut({ node: 노드 }) : 노드의 높이를 점점 줄이면서 사라지는 효과.
  • dojo.fx.Toggler(args) : 지정한 효과를 사용해서 노드를 show/hide() 하는 도우미 클래스. 동일한 효과로 show/hide()를 반복할 경우 편리하게 쓸 수 있다.
백문이불일견, 백견이불여일런!
말로 설명하려고 해도 말재주가 부족하니... 소스코드로 때우기로 하자.
<html>
<head>
<script type="text/javascript" djConfig="isDebug:true" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>
<style type="text/css">
#overlay { z-index:999; position:absolute; overflow:hidden; top:0; left: 0; right:0; bottom: 0; width:100%; height:100%; background:#000; }
#lightbox { z-index:1000; position:absolute; overflow:hidden; top:0; left:0; background:#fff; }
#lightbox div { border:1px solid #000; padding:20px; }
</style>
<script type="text/javascript">
dojo.require('dojo.fx');

var showLightbox = function() {
  var s1 = dojo.fadeIn({ node:'overlay', end: 0.5 });
  var s2 = dojo.fx.wipeIn({ node:'lightbox' });
  var s3 = dojo.fx.slideTo({ node:'lightbox', top:100, left:0 });
  var s4 = dojo.fx.slideTo({ node:'lightbox', top:200, left:300 });
  fx = dojo.fx.chain([s1, s2, s3, s4]);
  dojo.connect(fx, 'onBegin', function() {
    dojo.style('overlay', 'display', 'block');
    dojo.style('lightbox', 'display', 'block');
    fx.stop();
  });
  fx.play();
};

var hideLightbox = function() {
  var h1 = dojo.fx.slideTo({ node:'lightbox', top:200, left:0 });
  var h2 = dojo.fx.slideTo({ node:'lightbox', top:0, left:0 });
  var h3 = dojo.fx.wipeOut({ node:'lightbox' });
  var h4 = dojo.fadeOut({ node:'overlay' });
  var fx = dojo.fx.combine([h1, h2, h3, h4]);
  dojo.connect(fx, 'onEnd', function() {
    dojo.style('overlay', 'display', 'none');
    dojo.style('lightbox', 'display', 'none');
    fx.stop();
  });
  fx.play();
};

dojo.addOnLoad(function() {
  dojo.style('overlay', 'display', 'none');
  dojo.style('lightbox', 'display', 'none');
});
</script>
</head>
<body>

<p>Click the picture to show in the light box:</p>
<img src="photo.jpg" width="80" onclick="showLightbox()" />

<div id="overlay"></div>

<div id="lightbox">
  <div>
    <img src="photo.jpg" onclick="hideLightbox()" />
  </div>
</div>

</body>
</html>

페이지가 로딩된 다음, 작은 이미지를 클릭하면 뭔가 어수선한 애니메이션이 나오고 창(레이어)에 큰 이미지가 표시된다. 큰 이미지를 클릭하면 역시 어수선한 에니메이션이 나오고 창(레이어)이 닫힌다. 쉽게 얘기해서 어수선한 LightBox 다. 나도 안다... 하나도 안 비슷하다는 거... 그래도 조금만 손을 보면... -.-;;;;
중간에 보면 dojo.fx.combine()dojo.fx.chain()을 쓴 부분이 있는데... 위의 코드를:
dojo.fx.chain([f1, dojo.fx.combine([f2, f3]), f4]); 처럼 바꾸면 f1이 먼저 진행되고, f2와 f3는 동시에 진행되고, 그 다음에 f4가 진행된다. 예를 들려다보니 저렇게 됐지만, 잘 엮으면 멋진 효과를 쉽게~ 만들 수 있다. 정말 잘~ 엮어야 된다. 뭔 소린지는 엮어 보면 안다. -.-;;;
그리고 dojo.addOnLoad()를 사용해서 페이지가 로딩된 직후 overlay와 lightbox노드를 숨기고(display: none)있는데, 이는 보이지 않는 노드에 대해서 높이 계산을 안하는 불여우의 버그(또는 기능)를 피하기 위한 꼼수다.

혹시 prototype을 사용하고 있다면 script.aculo.us를 사용해서 비슷한 효과(더욱 현란한 효과)를 낼 수 있다. prototype과 scrit.aculo.us에 관심이 있는 분들은 인사이트에서 번역 출판한 프로토타입과 스크립타큘러스를 참조하시라(절때! 내가 추천글을 썼다거나 교정을 봤다거나 해서 이러는 건 아니고...-.-;;;; 프로토타입 관련 책 중에서는 원서도 제일 좋고, 번역도 제일 좋다).

오늘은 이 정도로 하고... 다음은 이벤트 시스템~

Posted by iolo
hacking/web2008/07/29 00:43
크리에이티브 커먼즈 라이선스
Creative Commons License
할 수 있는데 까지 해보자.

DOM 노드 위치/좌표 관련 함수들
CSS만으로 모든 레이아웃을 정확하게 계산하기란 쉽지 않다. 디자이너의 현란한 디자인이 IE의 더블마진 버그와 만나는 순간... 때문에 레이아웃 잡는게 여간 골치아픈게 아니다. 그래서 이런게 필요하다:
  • dojo.marginBox(domNode) : 지정한 DOM 노드의 margin box를 얻는다.
  • dojo.marginBox(domNode, {l:가로좌표, t:세로좌표, w:너비, h:높이}) : 지정한 DOM 노드의 위치/크기를 margin box로 설정한다. 위치는 부모 노드의 위치에 대한 상대좌표다(즉, CSS의 position:absolute 다). margin/padding/border는 바뀌지 않지만, content box의 크기는 바뀐다. 기본 단위는 픽셀(px)이다. 각 속성은 생략할 수 있다.
  • dojo.contentBox(domNode) : 지정한 DOM 노드의 content box를 얻는다.
  • dojo.contentBox(domNode, {l:가로좌표, t:세로좌표, w:너비, h:높이}) : 지정한 DOM 노드의 content box의 위치/크기를 설정한다. 위치는 부모 노드의 위치에 대한 상대좌표다(즉, CSS의 position:absolute 다) margin/padding/border는 바뀌지 않지만, margin box의 크기는 바뀐다. 기본 단위는 픽셀(px)이다. 각 속성은 생략할 수 있다.
사용자 삽입 이미지
위의 그림은 CSS의 박스모델을 설명하는 것인데, dojo의 contentBox는 위의 그림에서 맨 안쪽의 content를 둘러싼 사각형을, marginBox는 맨 바깥쪽의 margin까지 포함한 사각형을 의미한다. 이 결과는 IE이건 아니건, Quirks Mode이건 아니건 동일하다.
웬만하면 CSS로 처리하는 것이 바람직하지만, iframe이나 textarea같은 꼴통들에겐 dojo.contentBox/marginBox()가 도움이된다. 간단한 예를 들어보면(저번에 예제를 하나도 안만들어서 이번엔 좀 길게 만들어 봤다):
<html>
<head>
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>
<style type="text/css">
body { margin:0; padding:0; height:100%; overflow:hidden; }
#wrapper { width:100%; height:100%; }
#header { height:20px; background:#9cf; }
#content { width:100%; position:absolute; top:20px; bottom:0; background:#ccc; }
#frame { width:100%; height:100%; overflow:auto; }
</style>
<script type="text/javascript">
if (dojo.isIE) {
  var onResize = function() {
    var box1 = dojo.contentBox('wrapper');
    box1.t = 20;
    box1.h -= 20;
    dojo.marginBox('content', box1);
  };
  dojo.connect(dojo.global, 'resize', onResize);
  dojo.addOnLoad(onResize);
}
</script>
</head>
<body>
<div id="wrapper">
  <div id="header">Hello,World!</div>
  <div id="content"><iframe id="frame" src="http://dojotoolkit.org/" frameborder="no"></iframe></div>
</div>
</body>
</html>

이 예제의 목적은 스크롤바 없이 화면에 꽉 채운 페이지를 만드는 것이다. IE에선 부모 노드의 크기가 %로 지정되면 right/bottom 속성이 동작하지 않기때문에 곤란하다. IE의 CSS expression을 써도 되겠지만, 개인적으로는 이 방법을 선호한다. CSS만으로 어떻게 할 수 있을 것 같긴한데... 내공 부족 -.-;;;(표준 CSS만으로 할 수 있는 좋은 방법이 있으면 알려주시면 콩다방 커피 한잔 대접합니다~). 예제를 위한 예제이다 보니 아직 설명한 것들이 잔뜩 있는데 핵심은 중간 쯤에 있는 자바스크립트 코드다. 중간에 있는 if (dojo.isIE) { ... } 스크립트(주황색 배경)를 지우고 IE에서 실행시켜보시라. 나중에 dijit layout widget을 사용하면 이것보다 훨씬 복잡한 작업을 한 방에 해치울 수 있다!

DOM 편의 함수
앞에서 알아본 dojo.attr()/dojo.style()dojo.*Class() 외에도 잡다한 편의함수들이 많다. 이 함수들의 완전한 목록은 dojo API Reference에서 찾아보시고~ 여기서는 맛보기로 생각나는 것 몇 개만 알아보자:
  • dojo.place(domNode, refDomNode, position) : domNode를 refDomNode를 기준으로 위치/순서를 변경한다. position은 인덱스(숫자) 또는 before/after/first/last 중의 하나다. position 인자에 따라 appendChild/insertBefore() 등의 DOM API를 적절히 호출한다. 처음엔 복잡해 보이겠지만, 익숙해지고 나면 DOM API가 얼마나 구린지(?), 그리고 dojo.place()가 얼마나 자연스러운지 알게 될 것이다.
  • dojo.isDescendant(domNode, ancestorDomNode) : domNode가 ancestorDomNode의 하위 노드인지 확인한다.
  • dojo._destroyElement(domNode) : 지정한 노드를 해제한다. IE에서는 이벤트 핸들러가 걸린 노드와 관련한 메모리가 새는 버그가 있어서 domNode.parentNode.removeChild(domNode) 또는 domNode.parentNode.innerHTML = '' 또는 domNode.ownerDocument.detachNode(domNode) 로는 충분하지 않다. domNode.parentNode.innerHTML'_'로 시작하는 private함수지만 public으로 해도 무방할 정도로 유용하다.
  • dojo.setSelectable(domNode, selectable) : domNode와 모든 자식노드들을 선택불가능하게(마우스로 긁을 수 없게) 만든다. 이걸 활용하면 블로그 본문 긁지 못하게 하는 것을 쉽게 할 수 있겠지만... 이런 짓 하지말자. 어차피 긁을려면 다 긁는다. 다만, 메뉴나 툴바 같은 녀석들을 이 함수를 사용해 긁지 못하게 하면 잡다한 오동작을 원천봉쇄할 수 있다.
  • dojo._getOpacity(domNode) : domNode의 투명도를 얻어온다. 0이면 완전 투명, 1이면 완전 불투명이다. 이 함수 없이 할려면 IE이냐 아니냐에 따라서 삽질을 좀 해야 한다.
  • dojo._setOpacity(domNode, opacity) : domNode의 투명도를 설정한다.
이 함수들을 직접 쓸 기회는 많지 않겠지만 알아두면 유용할 때가 금방 온다.

(중간에 dojo API Reference가 있다고 얘기했다. 아는 사람은 다 알겠지만... 이걸 지금까지 얘기안한 이유가 있다. 이거 보고 괜히 dojo를 오해하지 말기 바란다. 이렇게 느려터지게 만드는 것도 쉬운 일이 아니다. 굳이 API가 필요하다면 이것 보다는 dojo toolbox를 쓰길 권한다.)

사용자 삽입 이미지
유틸리티 함수는 일단 마무리~
다음에는 재미있는(?) 애니메이션/효과 관련 함수들을 간단히 알아보고,
이어서 이벤트 시스템, 클래스 시스템, 그리고 dijit... 갈 길이 멀구나...

Posted by iolo
hacking/web2008/07/24 17:49
크리에이티브 커먼즈 라이선스
Creative Commons License
남아 있는 유틸리티 함수들 중에서 정말 자주 쓰이는 몇가지만 더 알아보자.

dojo.byId(id)
document.getElementById(id)와 동일하며 프로토타입$(id)와 동일하다.
지정한 id를 가진 DOM 노드를 찾는다. 참고로 dijit.byId(id)와는 전혀 다른 녀석이니 헷갈리지 않기를... 그리고 다른 window(frame/iframe)의 노드를 찾고 싶을 때는 dojo.withGlobal(window,'byId',dojo,[id]) 처럼 하면 된다(뭐가 이렇게 복잡하냐고? 그래도 없는 것 보다는 낫다).
$()보다 길어서 타이핑하기 귀찮겠지만... 덕분에 프로토타입이나 jQuery와 섞어서 사용해도 아무런 문제를 읽으키지 않는다. 굳이 $()를 쓰고 싶으면 예전에 쓴 블로그를 참조하시길...

dojo.attr() - DOM 속성 관련 함수들
dojo.attr()은 getter/setter 두가지 역할을 겸하고 있으며, domNode 대신 해당 노드의 id를 문자열로 지정해도 된다.
  • dojo.attr(domNode, attrName) : 지정한 DOM 노드의 지정한 속성 값을 가져온다. domNode.getAttribute(attrName)와 비슷하다.
  • dojo.attr(domNode, attrName, attrValue) : 지정한 DOM 노드의 지정한 속성 값을 변경한다. domNode.setAttribute(attrName, attrValue)와 비슷하다. 참고로, dojo 1.1.1 이후 버전에서는 attrName/Value 쌍을 배열로 지정할 수 있다. 예를 들면: dojo.attr(domNode, { action: 'add.php', method: 'POST' });
  • dojo.removeAttr(domNode, attrName) : 지정한 DOM 노드의 지정한 속성을 삭제한다. domNode.removeAttribute(attrName)와 비슷하다.
domNode.setAttribute/getAttribute/removeAttribute를 사용하면되는데 왜 이런게 필요하냐고 물으신다면... 자바스크립트 닭질을 좀 더 하시길 권해드리는 바이다. 일단 dojo에서 이런 걸 제공한다는 사실만 기억해두면 조만간 고맙게 쓰게 될 날이 온다.

dojo.style() - DOM CSS 속성 관련 함수들
dojo.style()도 getter/setter 두가지 역할을 겸하고 있으며, domNode 대신 해당 노드의 id를 문자열로 지정해도 된다.
  • dojo.style(domNode, cssAttrName) : 지정한 DOM 노드의 스타일 중에서 지정한 CSS속성 값을 가져온다. 주의 할 점은 cssAttrName은 CSS 형식(font-size, left-padding ...)이 아닌 자바스크립트 형식(fontSize, leftPadding ...)으로 지정해야 한다는 것이다. 참고로, dojo 1.1.1 이후 버전에서는 CSS 형식과 자바스크립트 형식 둘 다 사용할 수 있으며, cssAttrName/Value 쌍을 배열로 지정할 수 있다. 예를 들면: dojo.style(domNode, { fontSize: '20pt', 'text-decoration': 'underline' });
  • dojo.style(domNode, cssAttrName, cssAttrValue) : 지정한 DOM 노드의 스타일 중에서 지정한 CSS속성 값을 변경한다.
dojo.style()함수는 계산된 스타일(computed style)을 대상으로 한다. 즉, 캐스캐이드된 여러가지 CSS속성들이 모두 적용된 상태를 기준으로 값을 얻어오거나 변경한다.

dojo.*Class() - DOM CSS 클래스 관련 함수들
별거 아닌거 같지만 짱 편한 함수 몇 개 소개한다. 이런 짓 해보신 적 없으신가?
domNode.className = domNode.className + ' ' + 'newClass'; // 공백 주의!
domNode.className = domNode.className.replace('oldClass', ' ');

이게 중간 중간 공백 신경 쓰려면 열라 귀찮다. 아무튼 이런 닭질은 이젠 안녕이다.
  • dojo.addClass(domNode, cssClassName) : 지정한 DOM 노드에 지정한 CSS 클래스를 추가한다. cssClassName에는 여러 개의 클래스 이름을 공백으로 구분하여 지정해도 된다.
  • dojo.removeClass(domNode, cssClassName) : 지정한 DOM 노드에서 지정한 CSS 클래스를 제거한다. cssClassName에는 여러 개의 클래스 이름을 공백으로 구분하여 지정해도 된다.
  • dojo.toggleClass(domNode, cssClassName) : 지정한 DOM 노드에서 지정한 CSS 클래스를 갖고 있으면 제거하고, 없으면 추가한다.
  • dojo.hasClass(domNode, cssClassName) : 지정한 DOM 노드가 지정한 CSS 클래스를 갖고 있는지 확인한다.
dojo.attr()/dojo.style()/dojo.*Class()함수들은 dojo.query()와 함께 쓰면 더욱 편리하다. dojo.query에 대해서는 다음에 따로 알아보기로 하고, 예를 하나만 들어보면:
dojo.query('tr').forEach(
    function(node, i) {
        dojo.addClass(node, (i % 2) ? 'even' : 'odd');
    }
);

유틸리티 함수는 세 번으로 끝낼려고 했는데... 생각보다 길어졌다.

다음에 남은 유틸리티 함수들을 알아보고, 그 다음에 에니메이션 관련 함수들 알아보기로 하고... 오늘은 여기까지~

Posted by iolo
hacking/web2008/07/20 16:54
크리에이티브 커먼즈 라이선스
Creative Commons License
웹 프로젝트에서 자바스크립트의 비중이 점점 커지면서, JSLint 같은 검증 도구의 필요성이 날로 높아지고 있다 이걸 매번 소스코드를 클립보드로 복사(copy)해서 jslint.com의 웹 폼에 붙여넣고(paste) 돌리는 짓을 하다가 귀찮아서 몇가지 방법을 찾아 보았다.

먼저, maven:

pom.xml에 이런거 대충 추가하자. 그러면 mvn site 돌릴때 같이 실행되서 target/site/jslint/index.html에 보고서가 만들어진다. 중간에 sourceDirectory는 잘 고쳐 주시길... 안고쳐주면 src/main/javascript 가 기본값이다.

    <reporting>
...
        <plugins>
...
            <plugin>
                <groupId>org.codehaus.mojo.javascript</groupId>
                <artifactId>javascript-report-maven-plugin</artifactId>
                <configuration>
                    <sourceDirectory>src/main/webapp/js</sourceDirectory>
                    <encoding>UTF-8</encoding>
                    <assumeBrowser>yes</assumeBrowser>
                </configuration>
            </plugin>
...
        </plugins>
...
    </reporting>

site까지 돌리지 않고 수시로 확인하고 싶다면, pom.xml에 이런거 대충 추가자. 그러면 mvn javascript-report:jslint 명령을 사용하여 수시로 확인할 수 있다.
    <build>
...
        <plugins>
....
            <plugin>
                <groupId>org.codehaus.mojo.javascript</groupId>
                <artifactId>javascript-report-maven-plugin</artifactId>
                <configuration>
                    <sourceDirectory>src/main/webapp/js</sourceDirectory>
                    <encoding>UTF-8</encoding>
                    <assumeBrowser>yes</assumeBrowser>
                </configuration>
            </plugin>
...
        </plugins>
...
    </build>

compile 페이즈에서 실행하고, 에러나면 중단해버리고 싶은데... 보시다시피 플러그인 이름부터 report용 플러그인이다보니... 잘 안된다.

아... 이 녀석이 아직 정식 릴리즈가 안되서.. mojo 홈페이지의 문서를 참조해서 mono의 snapshot 플러그인 리파지터리를 활성화시켜야 한다.

다음으로, ant:

사실 maven으로 하기전에 먼저 ant로 했었다.

build.xml에 이런거 대충 추가해주자. 그러면, ant verify 명령을 사용하여 수시로 확인할 수 있다.
    <target name="verify">
        <scriptdef name="jslint" src="etc/fulljslint-ant.js" language="javascript">
            <attribute name="options" />
            <element name="fileset" type="fileset" />
        </scriptdef>
        <jslint>
            <fileset dir="src/main/webapp/js">
                <include name="**/*.js" />
            </fileset>
        </jslint>
    </target>

중간에 있는 자바스크립트 소스 디렉토리는 잘 고쳐 주시길... 물론 이렇게 하지 않고 <property name="js.srcDir" location="src/main/webapp/js" /> 이런식으로 쓰게 되겠지만...

더 중요한 것은 위쪽에 있는 fulljslint-ant.js인데, JSLint 홈페이지에 있던 크록포드옹의 코드에를 다운받아서 다음의 코드를 추가한 것이다:
importClass(java.io.File);
importClass(java.io.FileInputStream);
importClass(java.io.InputStreamReader);
importClass(Packages.org.apache.tools.ant.util.FileUtils);

function checkFile(file, options) {
    var reader = new InputStreamReader(new FileInputStream(file), "UTF-8");
    var input = new String(FileUtils.readFully(reader));
    input = input.toString();
    if (!input) {
        print("Couldn't open file '" + file.toString() + "'.");
        return;
    }
    if (!JSLINT(input, options)) {
        print("Problems found in " + file.toString());
        for (var i = 0; i < JSLINT.errors.length; i += 1) {
            var e = JSLINT.errors[i];
            if (e) {
                print('Lint at line ' + (e.line + 1) + ' character ' +
                        (e.character + 1) + ': ' + e.reason);
                print((e.evidence || '').
                        replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
                print('');
            }
        }
    } else {
        print("No problems found in " + file.toString());
    }
}

var options = attributes.get("options") || "{ browser:true }";
project.log('Running jslint....');
project.log('\toptions=' + options);
options = eval('(' + options + ')');

//var options = {eqeqeq : false, white: true, plusplus : false, bitwise : true, passfail: false, browser: true, evil: true, forin: true, newprimitive: true};
if (elements.get("fileset").size() > 0) {
    var fileset = elements.get("fileset").get(0);
    var ds = fileset.getDirectoryScanner(project);
    var srcFiles = ds.getIncludedFiles();
    for (var i = 0; i < srcFiles.length; i++) {
        var jsfile = new File(fileset.getDir(project), srcFiles[i]);
        checkFile(jsfile, options);
    }
}

코드가 좀 지저분해도 이해해주시길... =3=3=333

혹시, 아직도 jslint로 검사하지 않은 자바스크립트 코드를 deploy하고 있다면 지금 바로 가까운 벽으로 달려가서... 두 손 번쩍 들고... 반성하자. 그리고 지금이라도 (일단 간단하게 copy & paste로) jslint를 돌려보자.
사용자 삽입 이미지
좌절할 필요는 없다. 이제부터 고치면 된다.
사용자 삽입 이미지
참고로... 말해두지만... jslint.com에 괜히 이런 메시지가 있는게 아니다...

WARNING: JSLint may hurt your feelings.

=3=3=333
Posted by iolo
hacking/web2008/07/19 16:56
크리에이티브 커먼즈 라이선스
Creative Commons License
자바스크립트에는 두 가지 타입 검사 연산자가 있다: instanceoftypeof

그런데 이게 미묘하다. 예를 들어:
var hello = "hello"; 
alert(typeof hello); // string
var world = new String("world");
alert(typeof world); // object -,.-;;

dojo를 사용해보면 어떨까?
alert(dojo.isObject(hello)); // false
alert(dojo.isObject(world)); // true
alert(dojo.isString(hello)); // true
alert(dojo.isString(world)); // true

말나온 김에 한 가지만 더 예를 들어보면:
function test2() {
  alert(typeof arguments); // object
  // alert(arguments.join(',')); // 에러 -,.-;;;
  var args = []; // new Array();
  for (var i = 0; i < arguments.length; i++) { args[i] = arguments[i]; };
  alert(typeof args); // object typeof는 "array"를 모른다! -.-;
  alert(args.join(',')); // hello,world,1,2,3
}
test2('hello', 'world', 1, 2, 3);

dojo를 사용해보면 어떨까?
alert(dojo.isArray(arguments)); // false
alert(dojo.isArray(args)); // true
alert(dojo.isArrayLike(arguments)); // true
alert(dojo.isArrayLike(args)); // true

위의 것들은 생각나는 것을 예로 든건 뿐이고, 자바스크립트로 코딩하다보면 더 미묘한 경우도 많다. 그래서... dojo에는 이런 것들이 있다:

  • dojo.isString(arg) : arg가 문자열이면 true
  • dojo.isObject(arg): arg가 객체이면 true
  • dojo.isFunction(arg): arg가 함수이면 true
  • dojo.isArray(arg): arg가 배열이면 true
  • dojo.isArrayLike(arg): arg가 유사배열이면 true

그냥 익혀두고 쓰면 날로 편한케 하고져 할 따름이다. 찝찝하다면 그냥 알아만 두자. 자바스크립트로 먹고 살다보면 아쉬울 때가 곧 올 것이다.

이것만으로 끝내기 아까우니까 dojo의 브라우져 검사 기능을 간단히 알아보자:

  • dojo.isFF : 파이어폭스라면 메이저 버전 번호(숫자; 1.5, 2, 3)가 들어있다.
  • dojo.isIE: IE계열이라면 6, 7, 8 등의 메이저 버전 번호가 들어있다.
  • dojo.isSafari: 사파리라면 버전이 들어있다.
  • dojo.isOpera: 오페라라면 버전이 들어있다.
  • dojo.isMozilla: Gecko 기반 브라우져(Mozilla, Firefox, Camino 등)라면 Gecko 버전이 들어있다.
  • dojo.isKhtml: KHTML 기반 브라우져(Safari, Konqurer 등)라면 버전이 들어있다.
  • 기타 dojo.isBrowser, dojo.isQuirks, dojo.isGears, dojo.isAir, dojo.isRhino, dojo.isSpidermonkey 등이 있다.

이게 생각보다 편하다. 예를 들면:
if (dojo.isFF) {
  // FF workaround...
} else if(dojo.isIE) {
  // IE 공통 workaround...
  if (dojo.isIE === 6) {
    // IE6 전용 workaround...
  }
}
if (!dojo.isIE && !dojo.isMozilla) {
  alert('sorry unsupported!');
  return;
}
// 브라우져 공통 ...

직접(!) 제작한 짤방 하나 소개하며... 오늘은 여기까지~
사용자 삽입 이미지


덧 1. dijit을 사용하게 되면 위의 속성들을 참조해서 다음과 같은 css클래스를 html 태그에 추가해주므로, 브라우져별 css 핵을 적용할 때 편하게 사용할 수 있다:
dj_ie, dj_ie55, dj_ie6, dj_ie7, dj_iequirks, dj_opera, dj_opera8, dj_opera9, dj_khtml, dj_safari, dj_gecko, dj_ff2

덧 2. 나중에 얘기할 기회가 있겠지만(전에 했던가...-.-) 위의 예를 쉽게 테스트 해보려면 그냥 다음과 같은 태그를 다른 <script> 태그보다 앞에 추가해주면 된다:
<script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"></script>


Posted by iolo
hacking/web2008/05/13 16:47
크리에이티브 커먼즈 라이선스
Creative Commons License
자바스크립트에는 URL 인코딩과 관련해서 4가지 함수가 있다.
encodeURI(), encodeURIComponent(), escape()/unescape() 이 그것인데...
구글신께 여쭈었더니... 이렇게 다르다고 말씀해 주셨다.

정말?
일단, 실험을 해보기로 했다.

저 사이트에 나온 파일을 UTF-8EUC-KR로 각각 저장했다.

test-utf8.html, test-euckr.html
<html>
<body>
<script type="text/javascript">
var s;
s = encodeURI('http://www.google.co.kr/소 설.html');
document.write('<p>' + s + '<p>');
s = encodeURIComponent('http://www.google.co.kr/소 설.html');
document.write('<p>' + s + '<p>');
s = escape('http://www.google.co.kr/소 설.html');
document.write('<p>' + s + '<p>');
</script>
</body>
</html>

그리고 각각의 파일의 헤더 영역에 다음의 메타 태그들을 끼워넣은 파일을 두개 더 만들었다.

test-utf8-meta.html
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />

test-euckr-meta.html
<meta http-equiv="Content-Type" content="text/html;charset=EUC-KR" />

그리고, 이 페이지들을 한글 IE7, 영문 IE6, 영문 IE7, FF 2.0 으로 브라우져로 테스트 했다. 혹시나 싶어서 IE의 경우엔 항상 "UTF-8로 URL을 보내기" 옵션도 바꿔가면서 해봤는데... 말그대로 URL을 보내는 것이 아니라서 차이가 없었다.

이런 삽질을 왜 하냐 싶겠지만...
내가 기대한 것은 첫번째 경우지만... 결과를 보면... 정말... 다들 제각각이다. -.-;;;;

test-utf8-meta.html, test_euckr.html, test-euckr-meta.html, 한글 IE7, FF
test-utf8-meta.html, 영문 IE6/7(한글 언어 팩 없음)
http://www.google.co.kr/%EC%86%8C%20%EC%84%A4.html
http%3A%2F%2Fwww.google.co.kr%2F%EC%86%8C%20%EC%84%A4.html
http%3A//www.google.co.kr/%uC18C%20%uC124.html

test-utf8.html, 한글 IE7
http://www.google.co.kr/????html
http%3A%2F%2Fwww.google.co.kr%2F%3F%3F%3F%3Fhtml
http%3A//www.google.co.kr/%3F%3F%3F%3Fhtml

test-utf8.html, 영문 IE6/7(한글 언어 팩 없음)
http://www.google.co.kr/%C3%AC%E2%80%A0%C5%92%20%C3%AC%E2%80%9E%C2%A4.html
http%3A%2F%2Fwww.google.co.kr%2F%C3%AC%E2%80%A0%C5%92%20%C3%AC%E2%80%9E%C2%A4.html
http%3A//www.google.co.kr/%EC%u2020%u0152%20%EC%u201E%A4.html

test-euckr.html, 영문 IE6/7(한글 언어 팩 없음)
test-euckr-meta.html, 영문 IE6/7(한글 언어 팩 없음)
http://www.google.co.kr/%C2%BC%C3%92%20%C2%BC%C2%B3.html
http%3A%2F%2Fwww.google.co.kr%2F%C2%BC%C3%92%20%C2%BC%C2%B3.html
http%3A//www.google.co.kr/%BC%D2%20%BC%B3.html

정리해보자:
  1. meta 태그는 반드시 넣어줘야 한다. 없으면... IE가 힘들어 한다.
  2. meta 태그가 있어도 영문 환경에서 한글 언어 팩이 안깔려있으면 euc-kr은 황~이다.
  3. URL을 통째로 인코딩할 때는 encodeURI(), URL의 파라메터만 인코딩할 때는 encodeURIComponent()를 쓰면 된다.
  4. escape()/unescape()는 잊어버려라.
  5. 왠만하면 URL에 인코딩이 필요한 꺼리(한글... 공백... 이런 거)는 넣지 말자.

덧1.
여기서 의문점 한가지 더! 그렇다면 자바의 java.net.URLEncoder는 어떨까?
결론은 이녀석은 자바스크립트의 encodeURI()와 동일하다.
주의할 점은 java.net.URLEncoder의 두개의 함수 중의 파라메터가 두개인 녀석(캐릭터 인코딩을 지정해주는)을, 두번째 파라메터를 "UTF-8"로 지정해서 사용해야 한다는 것이다. 파라메터가 한 개인 첫번째 녀석을 쓰면... 플랫폼의 기본 인코딩(-Dfile.encoding)을 따라가므로 개차반(?) 난다.
자바에선 이것 저것 다 잊어버리고... 그냥 바이트 배열로 뽑아서 commons-codec의 URLCodec을 쓰는게 정신 건강에 이롭다.

덧2.
나름 좀 한다는 개발자들 조차 인코딩과 캐릭터셋에 대해서 오락가락한다. 자바 API 개발자들 조차 헷갈리고 있으니...(java 1.6의 String#getBytes()와 1.3의 String#getBytes()의 파라메터 이름을 보시라~~. commons-codec의 URLCodecgetEncoding()getDefaultCharset()도 보시라~~). 오죽하랴마는... 인코딩은 인코딩이고, 캐릭터셋은 캐릭터셋이다. 말하자면, "유니코드(캐릭터셋)에 속한 글자들은 UTF-8(인코딩)이나 UTF-16(인코딩)등으로 표현할 수 있다." 정도 일까? 그러니까, UTF-8이건 EUC-KR이건, URL 인코딩을 하는 입장에선 그냥 바이트 배열일 뿐이다. 더 어렵나?? =3=3=333

Posted by iolo
hacking/web2008/03/15 14:19
크리에이티브 커먼즈 라이선스
Creative Commons License
IE8의 첫번째 공개 베타 버전이 나왔다.

뭐가 얼마나 달라졌길래... 마이너 업데이트 한번없이 바로 8.0인가?
자세한 내용은
MS의 공식 홈페이지를 참조하면 될 것이고...

가장 기대가 되는 것은 역시 표준 지원과 성능이다.
나만 그런 것이 아닌듯... 벌써 벤치마킹 결과가 나오기 시작했다.
시대가 시대이니 만큼 브라우져의 성능은 결국 네트웍, 자바스크립트, DOM의 성능으로 귀결되는데...

자바스크립트 쪽 성능을 비교한 그림을 보면:
사용자 삽입 이미지
IE8... IE7과 별차이가 없구려... 완전 실망입니다요~
사파리가 괜히 뜨는게 아니었다. 파이어폭스 3의 엄청난 향상도 눈에 띈다.
의외인것은 성능빼면 남는게 없는 오페라가 캐안습한 결과를 보인것인데...
테스트에 포함된 코드가 이벤트 프로퍼게이션 모델의 영향을 많이 받은 듯...

DOM 성능을 비교한 그림을 보면:
사용자 삽입 이미지
오호라... 장난하냐? 장난해! 라고 생각했으나...
테스트 코드가 IE8에서 돌아가지 않아서 IE7 흉내내기 모드를 사용했다고 하는군. (흉내낼 꺼리가 그렇게 없냐!)
정리해보면 오페라가 지지부진한 사이에 사파리와 파이어폭스가 역전! 오페라도 성능으로만 버티기 힘든 상황...

한동안 지지부진했던 불여우도 3.0 베타 버전들을 잇달아 내놓으면서 분위기 반전을 모색하고 있다:
사용자 삽입 이미지
@..@ 실제로 돌려보면 실감할 수 있을 정도로 차이가 난다.
특히, 자바스크립트를 험하게 쓰는 사이트일수록 효과가 크다.
바꿔말하면, 파이어폭스 2.x(Gecko 1.7)의 코드가 그만큼 구렸다는 얘기?

옆 길로 많이 샜지만... -,.-;;; 정리하면...
IE7은 IE6의 문제는 하나도 해결하지 못하고 새로운 문제만 잔뜩 만들어 낸 최악의
브라우져였다.
IE8에서도 비슷한 실수를 하는게 아닌가 우려도 많았지만, 우여곡절 끝에 해피엔딩~
IE6를 쓰던 사람은 IE8로 쉽게 업그레이드 하지 않겠지만,
IE7을 쓰던 사람은 거의 모두 IE8로 업그레이드 하게되길 바란다.
그렇게 되면... IE7 등장 이전으로 돌아가는 거다. IE6 vs W3C 표준 호환 브라우져.

유독 이 나라에만 창궐하고 있는 "한국적 웹 사이트 바이러스"에겐 또 한 번의 시련~!
개념없는 웹-개-디 열분들 일거리 많이 생겨서 좋으시겠네요~
이번엔 부디 개념 탑재하고 리뉴얼하셔서 두고두고 평안하시길...
(일거리 없어지니까 곤란한가요? 좀 더 크리에이티브한 일을 하는게 좋지 않아요? 아님말구~)

Posted by iolo
hacking/web2007/12/04 15:18
크리에이티브 커먼즈 라이선스
Creative Commons License
요렇게 해주면:
$ = dojo = dojo.mixin(function(){ return dojo.query.apply(dojo, arguments); }, dojo);

요런 식으로 쓸 수 있게 된다:
$.addOnLoad(function(){
   console.debug($("div"));
});

$("div").onclick(function() { alert("div clicked."); });

$.xhrPost({form: $("#myFormId")[0]});

흠... 너무 prototype스럽군... -.-;

위의 방법 말고도 다양한 변형들이 있다.

요는 prototype의 $가 그렇게 대단한 무언가가 아니라는 거다.

'hacking > web' 카테고리의 다른 글

IE8에 대처하는 우리의 자세...  (2) 2008/03/15
dojo 1.1 beta 릴리즈!  (0) 2008/02/19
dojo에서 $ 쓰기  (0) 2007/12/04
prototype사용자를 위한 dojo 입문 (5)  (0) 2007/11/24
prototype사용자를 위한 dojo 입문 (4)  (1) 2007/11/16
prototype사용자를 위한 dojo 입문 (3)  (0) 2007/11/15
Posted by iolo
hacking/web2007/11/16 00:16
크리에이티브 커먼즈 라이선스
Creative Commons License
제 4 장 이벤트

javascript로 심각한 코딩을 해본 사람이라면 누구나 사소한 브라우져들간의 차이에 좌절한 경험이 있을 것이다. 문제는 prototype이나 dojo같은 멋진 넘들이 넘쳐나는 세상에도 여전히 과거의 코드에 매여있는 사람들이 있다는 것이다.
 
일단, 이런 HTML이 있다고 생각하자:

...
<button id='okBtn'>OK!</button>
...

* DOM
var okBtn = document.getElementById('okBtn');
if (okBtn.addEventListener) {
  okBtn.addEventListener('click', ok_onclick, true);
} else {
  okBtn.attachEvent('onclick', ok_onclick);
  okBtn.captureEvents(Event.CLICK);
}
function ok_onclick(e) {
  if (!e) e = window.event;
  if (e.keyCode) code = e.keyCode;
  else if (e.which) code = e.which;
  ...
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation();
}

* prototype
Event.observe($('okBtn'), 'click', function(event) { ... } )

* dojo
dojo.connect(dojo.byId('okBtn'), 'onclick', function(event) { ... } )

결정적인 차이는(?!) prototype과 달리 dojo는 'on'을 항상 붙여야 한다(예: onclick, onchange)는 것이다. dojo의 위젯(dijit)들은 이벤트 이름을 대소문자를 섞어서 사용해서(예: onClick, onChange) 표준 이벤트들과 구별한다.

사실 dojo.connect()는 이벤트 핸들러 연결보다 더 많은 일을 한다. 실제 구현은 AOP의 before advice에 가깝다고 볼 수 있다. 즉, 일반적인 함수에 대해서도 적용 가능하다.

dojo는 페이지 load/unload 이벤트를 다른 이벤트와는 조금 다르게 취급한다:

* BOM
window.onload = function() { ... }
window.onunload = function() { ... }

* prototype
Event.observe(window, 'load', function() { ... });
Event.observe(window, 'unload', function() { ... });

* dojo
dojo.addOnLoad(function() { ... });
dojo.addOnUnload(function() { ... });

엄밀하게 따지면, dojo.addOnLoad()는 DOMContentLoaded 이벤트 핸들러를 연결한다. 이게 뭔지 아시는 분이라면 따로 설명이 필요 없을테고, 그게 뭐냐고 하시는 분이라면 몰라도 되는 분일테니... 여기서 이러쿵 저러쿵 설명 안하겠다.

dojo.connect(window, 'onload', function() { ... }); 라고 해도 비슷한 결과를 얻겠지만... 미묘~~한 부분이 있다.

마지막으로 dojo에는 Topic 이벤트 시스템이라는 특이한 녀석이 하나 더 있다:
dojo.publish('/some/topic', value1, value2);
dojo.subscribe('/some/topic', function(arg1, arg2) { ... } );

"익명/공용/전역 메시지 큐" 비슷한 것인데, AJAX의 첫번째 A(Asynchronous) 때문에(덕분에?) 꽤 유용하게 써먹을 수 있다. 자세한 내용을 늘 그랬듯이 온라인 문서를 참고하시길...

다음에는 OOP 지원 기능에 대해서 알아보기로 하고... 오늘은 요기까지~.~/

Posted by iolo
hacking/web2007/11/15 23:34
크리에이티브 커먼즈 라이선스
Creative Commons License
제 3 장 XMLHttpRequest

계속해서, XMLHttpRequest 관련 함수들을 살펴 보자.
 
BOM(Browser Object Model) 코드는... 열라 길다. -.-; 생략할려다가... prototype이나 dojo가 얼마나 많은 노가다를 줄여주는지 확인하는 차원에서 주욱 적어봤다. prototype과 dojo 코드는 얼추 비슷해 보이지만, 가만히 살펴보면 자질구레한 부분에서 조금씩 다르다:

* BOM
var xhr;
try {
  xhr = new XMLHttpRequest();
} catch (e) {
  try {
    xhr = new ActiveXObject("Msxml2.XMLHTTP");
  } catch (e) {
    try {
      xhr = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e) {
      // ... Orz
    }
  }
}
xhr.onstatechange = function() {
  select (xhr.readyState) {
  case 4: // loaded
    select (xhr.statusCode) {
    case 200: // ok
      break;
    case ...
    }
  case ...
  }
}
xhr.open('GET','your/url', true);
xhr.send('paramName1=' + encodeURIComponent(paramValue1) + '&paramName2=' + encodeURIComponent(paramValue));
...

* prototype
new Ajax.Request('/your/url', {
  method: 'GET', /* POST, PUT, DELETE ... */
  asynchronous: true,
  parameters: {
    paramName1: paramValue1,
    paramName2: paramValue2,
    ...
  }
  onComplete: function(xhr) { },
  onFailure: function(xhr) { }
});

* dojo
dojo.xhrGet({ /* xhrPost, xhrPut, xhrRawPost, xhrRawPut ... */
  url: '/your/url',
  sync: false,
  handleAs: 'xml',  /* xml, json, text */
  content: {
    paramName1: paramValue1,
    paramName2: paramValue2,
    ...
  },
  load: function(response, xhr) { },
  error: function(response, xhr) { }
});

차이점을 요약하면:
  • new 연산자를 쓰지 않는다(그냥 함수 호출이다).
  • 요청 메소드를 파라메터로 처리하지 않고, 요청 메소드별로 함수가 따로 있다(코멘트 부분 참조).
  • 요청 url을 별도의 파라메터가 아니라 다른 옵션들과 똑같이 취급한다.
  • 동기/비동기 모드를 지정하는 파라메터가 거꾸로다(당연히 이름도 asynchronous가 아니고 sync다).
  • 응답 형식을 지정할 수 있으며, 응답이 바로 콜백함수로 전달된다.(즉, json 응답의 처리 방법이 다르다.)
prototype처럼 성공/실패 여부에 따라 콜백 함수를 지정할 수도 있지만, 내 경우에는 dojo.Deferred(twisted의 deferred와 유사한데...)를 선호한다. 여기서는 많은 옵션들을 생략했는데, 자세한 것은 각각의 온라인 문서를 찾아보시라.

Ajax.Updater / Ajax.PeriodicalUpdater에 해당하는 녀석은 없다. 그냥 window.setInterval()과 domNode.innerHTML을 쓰면 되니까 그다지 아쉽지 않다. 그리고, dojo의 위젯(dijit) 중에 ContentPane이라는 녀석을 쓰면 이 모든걸 한 줄로 끝낼 수 있다.

dojo에는 XHMLHttpRequest 대신 <script>태그와 <iframe>태그를 사용하는 dojo.io.script와 dojo.io.iframe이라는 두개의 특별한 녀석들이 있다. AJAX의 Cross Domain 제한을 경험해본 개발자라면 귀가 솔깃할 만한 녀석들이다. 자세한 것은 역시 온라인 문서를 찾아보시라.

다음에는 이벤트 핸들링에 대해서 알아보기로 하고... 요기까지~

Posted by iolo
hacking/web2007/11/13 00:52
크리에이티브 커먼즈 라이선스
Creative Commons License
제 2 장 utility functions

유틸리티 함수들을 살펴보자. dojo에는 아쉽게도(?) prototype사용자들이 제일 좋아하는 함수 $()가 없다. 대신 dojo.byId()가 있다. 이게 귀찮다고 생각하시는 분이 계시겠지만 dojo 개발팀에서도 꽤 오랜 고민과 토론 끝에 내린 결론이다. 관심있는 분은 메일링을 뒤져보시라.

* 지정한 id를 가진 DOM node를 검색

* dom
var node = document.getElementById('abc');

* prototype
var node = $('abc');

* dojo
var node = dojo.byId('abc');

너무 길다고? 익숙해지면 별 차이없다. document.getElementById()보다는 짧지않은가! 거기다 나는 $ 기호에 알르레기반응이 있다. per~~~~~l 씨러=3=3=3=33

* 지정한 노드 이름(태그 이름) / CSS 셀렉터를 가진 DOM node들(배열)을 검색

* dom
var nodes = document.getElementsByTagName('div');

* prototype
var nodes = $$('div');
var nodes = $$('.item');
var nodes = $$('#title);
var nodes = $$('div.item');
...

* dojo

var nodes = dojo.query('div');
var nodes = dojo.query('.item');
var nodes = dojo.query('#title');
var nodes = dojo.query('div.item');
...

dojo.query()도 prototype이나 jquery와 비슷한 CSS 2.1 셀렉터를 지원한다. 더 자세한 내용은 온라인 문서를 찾아보시라.

나중에 얘기하겠지만 prototype에서 $$와 each()의 결합을 많이 쓰는 것처럼, dojo.query()도forEach()와 함께 쓰면 편리하다.

일단 자자~ -,.-;;;;

Posted by iolo