Dojo로 HTML 위젯 개발하기

http://www.ibm.com/developerworks/kr/library/tutorial/wa-dojowidgets/index.html

Igor Kusakov, Web client lead developer, IBM

2007 년 4 월 24 일

이 튜토리얼은 웹 응용 개발자인 Igor Kusakov가 쓴 글이며 Dojo를 이용한 HTML 위젯 개발의 기초를 다루며 이미지 첨부와 HTML 문서에 이벤트 처리 추가, 복합적인 위젯을 다루는 방법을 포함합니다. 나아가 일반적인 옛 형태의 자바스크립트 코딩과 Dojo를 사용한 것의 중요한 차이와 웹 응용 개발 고유의 복합적인 문제를 다루는 조언을 알려줄 것입니다.

이 튜토리얼은 Dojo 응용의 전체적인 구조나 다양한 Dojo 패키지를 설명하지 않습니다. Dojo 툴킷이 빠르게 성장하기 때문에 언급한 몇몇 문제가 변경될 수 있습니다.

시작에 앞서

이 튜토리얼에서 기대할 수 있는 것과 그것을 얻는 방법을 살펴보자.

이 튜토리얼에 대해

이 튜토리얼은 Dojo 툴킷을 이용하여 HTML 위젯 개발을 시작하는 걸 목표로 한다. Dojo HTML 위젯을 개발하는 것을 배울 것이며 매우 간단한 것에서 시작하여 복잡한 것을 작업할 것이다. 이 튜토리얼을 통해 복합적인 위젯과 다양한 이벤트 처리 대안에 대해 알게 될 것이다.

이 튜토리얼을 기술적이고 공정하게 쓰려고 했다. 이 문서는 Dojo로 개발 작업을 할 필요가 있는 대부분의 개발자에게 유용할 것이다.

필요한 사전지식

이 튜토리얼은 중급부터 고급 수준의 자바스크립트 기술과 경험을 지닌 프로그래머를 대상으로 썼다. 브라우저 단의 자바스크립트 개발 지식을 알아야 한다.

시스템 요구사항

예제를 실행하려면 Dojo 툴킷이 현재 지원하는 브라우저가 필요하다(Dojo FAQ 참고). 하드 디스크에 Dojo 툴킷을 다운로드해 압축을 풀어두고 몇개의 파일을 추가하기만 하면 웹 브라우저에서 예제 HTML을 실행할 수 있다.

Dojo 툴킷은 무엇인가?

Dojo 툴킷이 무엇이며 어디에 쓰는지, 어떤 강점이고 있고 현재 어떤 약점이 있는지 소개하겠다.

Dojo 툴킷 정의

Dojo는 멀티 플랫폼 자바스크립트 툴킷이다. 자바스크립트용 Dojo는 자바 언어를 위한 자바™ 런타임 라이브러리와 매우 비슷하다. 자바스크립트가 가장 널리 쓰이는 영역인 브라우저 단의 웹 개발에 Dojo가 사용된다.

전체적인 전망

최근에 웹 2.0과 Ajax 기술에 대한 열광을 보면 큰 사업에서도 자바스크립트를 진지하게 응용할 수 있는 준비가 된 것처럼 보인다. 자바스크립트 기반 프로젝트가 대체로 실패했던 1990년대 말에 비해 기술적인 발전이 많이 되었기 때문에 자바스크립트를 중요한 일에 사용하는 것은 좋은 생각이다. 지난 10여년 동안 자바스크립트 가상 머신은 성숙했고 브라우저의 호환성은 더 좋아졌다. 중요한 표준들도 나왔고 CPU의 연산 능력과 메모리의 용량은 비약적으로 증가했다. 게다가 자바스크립트 응용 개발에 대한 지식들이 축적되었다. Dojo 툴킷에는 그런 경험들이 코드에 녹아있다.

개념적인 접근

Dojo의 개념은 놀랍다. 첫 번째 주목할 것은 자바스크립트 개발을 높은 수준의 품질로 끌어올려준다는 것이다. 이 특성은 자바 언어의 영향을 받은 것으로 보인다. Dojo는 여러 다른 자바스크립트 프레임워크를 반영하여 기본 개념이 성숙되어 있다. 툴킷 방식이라 필요할 때만 사용할 수 있다. 프레임워크나 라이브러리 방식은 그렇게 사용할 수 없다. Dojo는 사업하기 좋은 오픈소스 라이선스를 가져 여러 프로젝트에 적합하다.

현행 문제

가장 큰 문제는 Dojo가 여전히 작업중이란 것이다. 출시 품질의 프로그램에는 적절하지 않는 부분이 아직 있다. 문서는 거의 없고 위젯 구조와 위젯의 일부만 부분적으로 다루고 있다. Dojo를 이해하는 최고의 방법은 여전히 코드 자체를 공부하는 것이다. 하지만 코드 자체를 공부하는 것은 입문자를 위한 좋은 방법이 아니다. 다행히 이 문제는 시간이 지나면 해결될 것이다.

다른 중요한 문제는 Dojo에 포함된 위젯에 대한 인식이다. 많은 사람들은(특히 관리자들) Dojo 위젯이 응용 프로그램에 쉽게 적용할 수 있는 "레고 부품"의 완벽한 집합이길 기대한다. 이것은 Dojo가 가야 할 길인데 아직까지 도달하지 못했다. 몇몇 Dojo 위젯은(트리 위젯 등) 충분히 일반화되었으나 대부분의 Dojo 위젯은 여전히 작업중이다. 그러한 위젯들은 "참고를 위해 구현"했거나 "시험삼아 구현"한 것이다. 방대한 요구사항을 적용할 상업적인 프로젝트에 적합한 품질이 아니다.

다른 기술 발전처럼 Dojo의 현재 제약에 대한 해결책은 Dojo 개발과 문서에 기여하는 것이고 이 튜토리얼 역시 그런 노력 중 하나다.

시작하기

이 튜토리얼을 위한 개발환경을 설정한다.

튜토리얼 개발환경 설정하기

튜토리얼을 위한 개발환경 설정은 비교적 쉽다. 아래 예제를 따라하면 된다. 사용하는 운영체제나 브라우저가 Dojo 툴킷이 지원하는 것이라면 아래 내용대로 하면 된다.

Dojo 툴킷 zip 파일을 http://dojotoolkit.org/에서 다운로드한다.

튜토리얼용 폴더를 C:\tutorial 등의 형태로 만든다.

Dojo zip 파일을 새로 만들어진 폴더에 압축을 푼다(예: C:\tutorial\dojo-0.3.1-ajax).

특정 버전의 Dojo 폴더의 이름을 dojoAjax로 바꾼다(예를 들어 C:\tutorial\dojo-0.3.1-ajax를 C:\tutorial\dojoAjax로 바꾼다).

코드 예제

이 튜토리얼의 예제 코드는 파일 세 개인데 이 파일들은 적절히 만들고 수정해야 한다. 튜토리얼을 읽으면서 예제 코드를 접할 것이다. 지금은 간단히 비어 있는 파일을 만들고 아래의 위치에 둔다(이클립스는 파일마다 적절한 탭을 제공한다. 하지만 메모장을 써도 무방하다).

test.html

C:\tutorial\test.html

dojoAjax/src/widget/HelloWorld.js

C:\tutorial\dojoAjax\src\widget\HelloWorld.js

dojoAjax/src/widget/template/HtmlHelloWorld.html

C:\tutorial\dojoAjax\src\widget\template\HtmlHelloWorld.html

* 파일 위치 : Dojo 내부 디렉토리에 튜토리얼 파일을 넣는 것은 주의해야 한다. 그것은 장기적인 프로젝트에서 좋은 방법이 아니다. Dojo 디렉토리 구조 밖에 코드를 두는 방법에 대해서는 Dojo 질답(참고자료)을 참고하기 바란다.

예제 코드를 접하면 적당한 파일에다 코드를 복사해 붙여넣는다. 그런 후 브라우저에서 test.html 파일을 연다. 파일을 저장한 후 브라우저를 새로 고치면 결과로 만들어진 위젯을 볼 수 있다(Ctrl 키를 누른 상태에서 다시 고침을 해야 캐시를 무시한다는 것을 명심하라. 캐시 문제에 대해서는 이 튜토리얼의 뒷 부분에서 다룰 예정이다).

이 튜토리얼의 예제 코드가 실행되지 않는 문제(브라우저에 위젯이 그려지지 않는 상황)를 경험한다면 dojo.require("dojo.widget.*");를 test.html이나 HelloWorld.js에 추가하면 된다. 필자는 이 문제를 재현하지 못했으므로 튜토리얼 예제 코드에는 이 줄이 추가되어 있지 않다.

Dojo HTML 위젯

이 절에서는 Dojo HTML 위젯이 무엇인지, 구성하는 파일이 무엇인지를 설명하고 위젯의 디렉토리 구조를 살펴본 후 위젯을 사용하는 첫 번째 예제를 보여주겠다.

Dojo 위젯은 무엇인가?

Dojo 위젯은 JSP의 커스텀 태그나 Tapestry의 <span jwcid="...">와 비슷하지만 웹 브라우저 단에서 처리된다. Dojo 위젯은 편리하게 재사용하기 위해 시각적인 웹 컴포넌트를 캡슐화한다.

Dojo 위젯 구조는 DOM 객체 구조에 독립적이다. 각 Dojo 위젯은 DOM 고유의 widgetId를 가지고 있으며 0개 이상의 DOM 요소(element)뿐만 아니라 자식 Dojo 위젯을 가진다.

위젯 부분

위젯은 여러 파일로 구성되어 있다. 자바스크립트 코드 파일은 필수적이고 다른 파일들은 선택적이다.

자바스크립트 코드 파일(*.js)은 자바스크립트로 된 위젯 로직을 담는다. 이 파일은 자바스크립트 DOM 객체 API를 사용하여 시각적인 로직을 담당한다(Dojo는 공통적인 기능을 단순화시켜줄 여러 가지 유용한 라이브러리를 제공한다).

HTML 템플릿(*.html)은 HTML로 된 기본 위젯 표시를 제공한다. 템플릿이 매우 단순하면 문자열로 코드 파일 속에 포함할 수 있다.

CSS 스타일 파일(*.css)은 시각적인 스타일을 포함한다. 이 내용은 HTML 템플릿이나 자바스크립트 코드에서 사용된다.

이미지 파일(*.gif, *.jpg 등)은 위젯이 사용할 이미지를 담는다.

그림 1. 위젯 디렉토리 구조

HTML 코드의 Dojo 위젯

이제부터 HTML에서 Dojo 위젯을 어떻게 정의하는지 알아보자. 예를 들어 "Button"이라고 불리는 표준 Dojo 위젯을 사용할 것이다. 이전에 만든 test.htm 파일에 아래 코드를 복사한 후 브라우저로 읽어들인다. 코드는 "Submit"이라고 적힌 Dojo 버튼 위젯을 보여주는 HTML 코드를 동적으로 생성한다.

Listing 1. test.hml: Dojo 버튼 위젯

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.Button");

</script>

</head>

<body>

<div dojoType="Button">Submit</div>

</body>

</html>

Listing 1에서 위젯 종류는 HTML <div> 요소의 dojoType 속성(attribute)으로 정의한다. Listing 2에서 보는 것처럼 유니크 태그로 Dojo 위젯을 정의할 수도 있다.

Listing 2. test.html: 유니크 태그로 정의한 버튼 위젯

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.Button");

</script>

</head>

<body>

<dojo:button>

Submit

</dojo:button>

</body>

</html>

첫 번째 방법(<div dojoType="Button">...)은 일반적인 방법으로 대부분의 브라우저에서 오랫동안 작동해왔다. 또 Dojo에 특화된 태그를 인식하지 못하는 HTML 편집기에서도 사용할 수 있다.

이 튜토리얼에선 첫 번째 방법을 사용할 것이다.

'Hello World' 위젯

전통적인 "Hello World" 위젯은 previous section에서 다룬 파일 구조나 디렉토리 구조보다 더 친숙할 것이다.

Hello World.js

Listing 3 은 HelloWorld 위젯에 필요한 자바스크립트 파일의 내용이다. 이 코드를 튜토리얼의 설정 부분에서 생성했던 적당한 파일에 저장한다.

Listing 3 . dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.html")

});

dojo.widget.HtmlWidget이 HelloWorld 위젯의 상위 클래스란 것에 주의하라.

Listing 4는 Listing 3의 예제 코드를 위해 만든 HTML 템플릿이다. 앞에서 만들었던 적당한 파일에 이 코드를 저장한다.

Listing 4. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div>

Hello World

</div>

아래의 HTML을 test.html 파일에 저장한 후 브라우저로 읽어들이면 "Hello World."라는 글귀를 볼 수 있다.

Listing 5. test.html: Hello World 테스트

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body>

<!-- as an HTML element with dojoType attribute -->

<div dojoType="HelloWorld"></div>

</body>

</html>

HTML 템플릿을 문자열로 제공하기

HTML 템플릿이 단순하다면 Listing 6처럼 자바스크립트 파일에 문자열로 저장하는 게 낫다.

Listing 6. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templateString: "<div>Hello World</div>"

});

위젯 개발의 기초

이 절에서는 Dojo HTML 위젯을 생성하는 기본적인 것 몇 가지를 다룬다. 위젯을 변경하기 위해 속성을 사용하며 HTML 템플릿에 코드 토막을 넣고 CSS를 참고하며 다양한 곳에 위치한 이미지 파일을 사용한다.

위젯 속성 사용하기

위젯의 행동과 뷰를 속성을 사용하여 수정할 수 있다. 예를 들어 HelloWorld 위젯을 수정하여 속성에 포함된 글을 출력할 수 있다. Listing 7, Listing 8, Listing 9의 코드를 적당한 파일에 복사하고 브라우저에서 test.html를 다시 읽어들인다. 위젯은 "This is text is passed as a widget attribute."라고 출력할 것이다.

Listing 7. test.html

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body>

<div text="This text is passed as a widget attribute"

dojoType="HelloWorld"></div>

</body>

</html>

Listing 8의 자바스크립트 코드는 속성 정의를 보여준다.

Listing 8. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.html"),

// widget attributes

text: "" // default value

});

속성의 기본 값을 반드시 부여해야 한다(Listing 8의 text 속성을 참고) 그렇지 않으면 그 속성들은 무시된다(Dojo는 test.html의 위젯을 정의하기 위해 사용한 DOM 노드의 속성 값들을 무시한다).

실제 값을 사용하는 코드에 값을 전송하는 코드는 Listing 9에 있다(다음 절에서 다룰 것이다.)

Listing 9. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div>${this.text}</div>

속성 처리하기

속성은 보통 (뒤에 언급할) postCreate() 메서드의 위젯 코드에서 처리된다. 또 다른 인기있는 부분은 fillInTemplate() 메서드다. 많은 Dojo 위젯에서 속성들이 postCreate()에서 처리된다는 것을 명심하라. 물론 정해진 속성의 값을 바꾸는 변경자(setter)도 있다(먼저 언급되었던 setText("...")와 같은 경우다). 이것들에는 두 가지 차이점이 있다. postCreate() 메서드를 사용하면 위젯 생성 때 속성 값을 지정하게 되고 변경자를 이용하면 동적으로 실행시간에 변경한다. 두 방법 중 하나를 일관되게 적용하는 것이 좋은 프로그래밍 습관이다.

HTML 템플릿의 코드 조각

HTML 템플릿에 코드를 포함하는 것은 나쁘게 보인다. 하지만 종종 필요한 경우가 있다. dojoRoot를 이미지를 위해 사용한다거나 속성을 직접 출력하거나 국제화를 위해 사용할 수 있다.

Dojo는 코드 조각을 이용하여 HTML 템플릿에 자바스크립트 코드를 포함시킨다. ${...} 표기법을 사용하면 코드가 위젯 객체 문맥에서 평가된다. 이론적으로는 HTML 템플릿에서 this 하위의 항목을 모두 사용할 수 있다. 하지만 (아래에서 언급할) dojoRoot 상수와 공개된 위젯 속성만 사용하는 것을 추천한다.

Listing 10은 HTML 템플릿에서 코드 조각을 어떻게 사용하는지 보여준다.

Listing 10. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div id="${this.widgetId}">

<img src="${dojoRoot}../images/yourimage.gif"/>

${this.text}

</div>

물론 다음에 논의할 내용처럼 HTML 템플릿 안에 이밴트 핸들러를 기술하는 방법도 가능한다.

CSS 추가하기

HTML 페이지에 이미 불러온 전역적인 CSS 파일이 있다면 HTML 템플릿과 자바스크립트 코드에서 CSS 클래스를 참조할 수 있다. 프로젝트 특화된 위젯에 괜찮은 방법이다.

하지만 전체적으로 위젯이 모두 갖추길 원하거나 여러 프로젝트에 재사용을 해야 한다면 Dojo가 지원하는 위젯별 CSS 파일을 사용하라. 이 파일은 관련된 위젯을 함께 자동으로 읽어들인다.

Listing 11은 자바스크립트 코드 파일의 위젯별 CSS 파일을 어떻게 정의하는지 보여준다.

Listing 11. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.html"),

templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.css")

});

Listing 12는 HTML 템플릿의 CSS 클래스를 사용하는 법을 보여준다.

Listing 12. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div class="helloWorld_caption">

Hello World

</div>

Listing 13은 Listing 12에서 참조한 클래스를 정의한 예제 CSS 파일이다.

Listing 13. dojoAjax/src/widget/template/HtmlHelloWorld.css

.helloWorld_caption {

font-family: Verdana;

font-size: 10pt;

}

CSS 클래스의 이름이 프로젝트에서 유일해야 한다는 것을 명심하라. 그렇기 때문에 CSS의 클래스 이름에 접두사를 붙이는 방법은 좋은 생각이다. 상속된 CSS를 프로그램적으로 생성한 DOM 요소에 적용하는 경우엔 별 문제가 없다.

이미지 참조하기

Dojo에서 자바스크립트 코드로부터 이미지를 참조하는 적절한 방법은 Dojo 루트 디렉토리로부터 상대 URL을 제공하는 dojo.uri.dojoUri 메서드를 사용하는 것이다. Dojo 파일 구조 외부의 파일이라면 ".."를 이용하여 찾아야 한다. 예를 들어 img.src = dojo.uri.dojoUri("../images/yourimage.gif");와 같은 방법이 있다.

Listing 14. 자바스크립트 코드 파일로부터(Dojo 루트 디렉토리에서 상대 경로로) 이미지 파일을 참조하기

var img = document.createElement("img");

// the dojo way

img.src = dojo.uri.dojoUri("src/widget/templates/images/yourimage.gif");

// relative to the page using this component (depends on page location,

// thus breaks encapsulation and is not recommended)

img.src = "dojoAjax/src/widget/templates/images/yourimage.gif";

Dojo에서 HTML 템플릿의 이미지를 참조하는 방법은 Listing 15에서 봤던 Dojo 루트 디렉토리에 상대적인 URL을 ${dojoRoot} 상수를 이용하여 만드는 것이다.

Listing 15. HTML 템플릿 파일에서(Dojo 루트 디렉토리에서 상대 경로로) 이미지 참조하기

<img src="${dojoRoot}src/widget/templates/images/yourimage.gif"/>

CSS 파일에서 이미지를 참조하기 위해 CSS 자체 특징을 사용할 수도 있다. Listing 16처럼 CSS 파일 자체가 위치한 디렉토리에서 상대 경로로 이미지를 참조한다.

Listing 16. (CSS 파일 위치에서 상대 경로로) CSS 파일에서 이미지 참조하기

background-image: url("images/yourimage.jpg");

/* Internet Explorer-only hack, relative to dojo root directory, not recommended */

background-image: expression(dojo.uri.dojoUri(

"src/widget/templates/images/yourimage.gif"));

위젯에 프로그래밍에 따라 접근하기

이 절에서는 HelloWorld 위젯에 약간의 코드를 추가한다. Dojo 툴킷에 전통적인 자바스크립트 프로그래밍 기술이 적용될 때 잘못될 수 있는 부분을 알게 될 것이다.

오래된 형태의 자바스크립트 방법으로 위젯에 접근하기

"Hello World" 문자를 동적으로 변경하기 위해 HelloWorld 위젯에 몇 가지 코드를 추가한다고 가정하자. Listing 17은 능숙한 자바스크립트 개발자가 Dojo 위젯을 다루기 위해 쓴 첫 번째 코드다.

Listing 17. test.html: 전통적인 방법으로 위젯 접근에 실패

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body onload="document.getElementById('someID').innerHTML='New text';">

<div id="someID" dojoType="HelloWorld"></div>

</body>

</html>

* Dojo 이벤트 시스템에 대해 더 알고 싶다면 참고자료를 참조한다.

어떤 결과가 나왔는지 알겠다! 이 코드는 전혀 작동하지 않는다. 무엇이 잘못되었는지 알아보자.

1. <body onload="..."> 속성 실패

자바스크립트 <body onload="..."> 속성은 Dojo 툴킷에서 호환되지 않는다. 대신에 Dojo는 자체 이벤트 시스템에 onload 이벤트를 감싸두었다. Listing 18은 "Dojo 방식"으로 쓴 같은 코드다.

Listing 18. test.html: Dojo 형태 onload 코드

<html>

<head>

...

<script>

dojo.addOnLoad(function(){

alert("onload!");

});

</script>

</head>

2. Dojo 위젯은 DOM 요소가 아니다

바로 그거다. 그게 전부이다. Dojo 위젯은 DOM과 독립된 실체(entity)로 보통 1개 이상의 DOM 요소를 가지고 있다.

Dojo가 위젯을 생성할 때 위젯을 정의하기 위해 사용한 DOM 노드(<div id="someID" dojoType="HelloWorld"> </div>)를 제거한다. 그래서 Dojo가 제어하기 위해 알고 있는 속성을 제외하고는 사라진다. 예를 들어 id 속성은 Dojo의 widgetId가 된다. 이 속성들을 위젯의 특정 DOM 노드에 넣고 싶다면 약간의 작업이 필요하다. 그 예로 Listing 19에서 HTML 템플릿을 이용하여 속성을 DOM 노드에 넣을 수 있다.

Listing 19. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div id="${this.widgetId}">

Hello World

</div>

위 예제에서 ${this.widgetId} 코드 조각을 DOM 노드의 id 속성을 위해 사용했다. widgetId는 Dojo 위젯 하부 구조의 유일한 ID로 정의된 표준 위젯 속성이다. 또한 이것을 DOM ID로 이용하는 것도 가능하다.

속성을 전송하는 또 다른 방법은 자바스크립트 코드 파일에서 fillInTemplate() 메서드를 재정의(override) 하는 것이다. 대개 "style" 속성을 전송하기 위해 이 메서드를 재정의한다.

혼합된 방법, 혼합된 결과

이제 오래된 형태의 자바스크립트 코드이지만 중요한 실수를 제거한 코드로 Dojo 컴포넌트에 접근할 수 있다. Listing 17에서 시도한 내용을 Listing 20으로 성공할 수 있다.

Listing 20. test.html: 전통적인 방법으로 Dojo 위젯에 접근하기

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

dojo.addOnLoad(function(){

document.getElementById("someID").innerHTML="New text";

});

</script>

</head>

<body>

<div id="someID" dojoType="HelloWorld"></div>

</body>

</html>

이 코드는 작동하지만 Dojo가 의도하는 방법은 아니다. 설명한 기법은 사실은 위젯 캡슐화가 안 된 좋지 않은 것이다. 그러나 자바스크립트 경험이 있다면 Dojo 위젯을 이와 같은 방식으로 시작할 것이다. 다음으로 Dojo 툴킷이 제안하는 방법을 살펴보자.

Dojo 식으로 위젯에 접근하기

다시 한번 HelloWorld 위젯의 글귀를 동적으로 바꿔보고 싶다면 이번엔 Dojo 식으로 해 보자. Listing 21처럼 HTML 템플릿과 자바스크립트 코드를 수정해 사용하자.

Listing 21. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div dojoAttachPoint="domNode">

Hello World

</div>

결합점

Dojo 위젯은 HTML 템플릿에 생성된 DOM 요소를 조작하기 위해 결합점(attachment point)를 이용한다. 결합접은 기본적으로 DOM 요소에 의해 명명된다. Dojo 방식으로 코딩한다면 id="${this.widgetId}"와 같은 구문을 사용할 필요가 없다. 루트 DOM 노드를 id를 통해 접근할 수 없고 결합점을 통해야 하기 때문이다.

* domNode : 루트 DOM 요소에 수동으로 domNode 결합점을 대입할 필요가 없다. 이것이 기본이기 때문이다. 수동으로 결합점을 대입하는 것은 하부 개념을 확실히 하기 위해 튜토리얼 용도에만 사용한다.

템플릿의 어떤 HTML 요소에든지 결합점을 대입할 수 있다. 루트 요소 결함점은 전통적으로 domNode라고 명명되어 있다. 다른 요소들은 원하는 컨벤션에 따라 이름을 붙여줄 수 있다. 결합점 이름을 위해 접미사를 노드에 추가하면 코드는 더 읽기 쉬워진다. 결함점은 위젯 생성 때 위젯 필드로 자동으로 할당된다. 위젯 코드의 결합점을 참조하려면 this.someAttachPointNode 표기를 사용한다.

Listing 22 는 동적 변경자가 있는 위젯 코드다. 변경자는 출력될 글귀를 바꾸기 위한 것이다. domNode 결합점이 어떻게 사용되는지 주의하라.

Listing 22. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.html"),

// dynamic setters

setHtml: function(htmlString) {

this.domNode.innerHTML = htmlString;

}

});

widgetId로 위젯 인스턴스 얻기

Dojo 툴킷은 Listing 23과 같이 widgetId를 이용해 동적으로 위젯 참조를 얻는 것이 가능하다.

Listing 23. widgetId로 위젯을 얻기

var widget = dojo.widget.manager.getWidgetById('someID');

// or, a short version:

var widget = dojo.widget.byId('someID');

// Gotcha: the following means document.getElementById('someID')

var widget = dojo.byId('someID');

최종 코드

Listing 24는 Dojo 방법으로 완성된 코드다. 위젯 코드에 의해 문구가 어디에 어떻게 출력될 모르고 추상 변경자(abstract setter)를 이용하는 것에 주목하라. 그래서 위젯은 사용자로부터 독립된 로직을 보여준다. 이것은 매우 대단한 일이다.

Listing 24. test.html

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript"> dojo.require("dojo.widget.HelloWorld");

dojo.addOnLoad(function(){

dojo.widget.byId("someID").setHtml("New text");

});

</script>

</head>

<body>

<div id="someID" dojoType="HelloWorld"></div>

</body>

</html>

동적으로 Dojo 위젯 만들기

이전 예제에서 test.html 파일 내에 정의해서(<div dojoType="HelloWorld"></div>) 정적으로 위젯을 만들었다. 물론 자바스크립트 코드 내에서 dojo.widget.createWidget() 메서드를 사용하여 동적으로 위젯을 생성할 수 있다.

Listing 25. test.html: 동적으로 Dojo 위젯 생성하기

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

dojo.addOnLoad(function(){

var newWidget = dojo.widget.createWidget(

"HelloWorld", // widgetType

{}, // widget attributes, for example {title: "Some Title"}

dojo.byId("widgetPlaceholder") // reference to a DOM node that

// will be REPLACED by new widget

);

});

</script>

</head>

<body>

<div id="widgetPlaceholder"></div>

</body>

</html>

dojo.widget.createWidget() 메서드는 2~4개의 인자를 가지며 마지막 2개는 약간 기교적이다.

첫 번째 인자는 위젯의 타입이다.

두 번째 인자는 위젯 속성의 해시다.

세 번째 인자는 DOM 노드이며 네 번째 인자에 따라 다른 방법으로 적용된다.

네 번째 인자가 없다면 DOM 노드는 (그 자신의 domNode에 의해 시작된) 새 위젯으로 교체된다.

네 번째 인자가 있다면 dojo.dom.insertAtPosition(node, ref, position) 메서드에 의해 위치가 결정되고 위젯은 세 번째 인자에 상대적으로 삽입된다(참조 노드가 대체되거나 삭제되지 않는다).

position 인자는 다음과 같다.

before: 위젯은 참조 노드 이전에 추가된다(그래서 이전 형제가 된다).

after: 위젯은 참조 노드 다음에 추가된다(그래서 다음 형제가 된다).

first: 위젯은 참조 노드의 첫째 자식이 된다.

물론 수동으로 삽입할 수 있다. 세 번째와 네 번째 인자를 기술하지 않고 Listing 26과 같이 원하는 위치에 위젯 domNode를 삽입할 수 있다.

Listing 26. test.html

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

dojo.addOnLoad(function(){

var newWidget = dojo.widget.createWidget(

"HelloWorld", // widgetType

{} // widget attributes, for example {title: "Some Title"}

);

dojo.byId("widgetPlaceholder").appendChild(newWidget.domNode);

});

</script>

</head>

<body>

<div id="widgetPlaceholder"></div>

</body>

</html>

dojo.widget.createWidget()이 부모/자식 관계를 형성하지 않는다는 점에 주의하라. 그래서 위젯의 계층 관계가 필요하다면 수동으로 관계를 만들어야 한다. 이 주제에 대해서는 앞으로 내포 위젯과 복합 위젯을 다룰 때 더 자세히 살펴보겠다.

내포 HTML

이 절에서는 Dojo HTML 위젯 생성을 포함하여 좀더 복잡한 문제를 몇 가지 고려할 것이다. 먼저 위젯 요소 속의 HTML을 다루는 여러 기술을 알아보겠다.

정적 내포 HTML

위젯 요소 내에 정적으로 정의한 HTML을 다뤄야 한다면 Listing 27을 참고하라.

Listing 27. test.html: 정적 내포 HTML 예제

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body>

<div dojoType="HelloWorld"> Some user-specific <b>HTML</b></div>

</body>

</html>

Dojo는 위젯을 생성할 때 그것을 정의하기 위해 사용한 DOM 요소를 삭제한다. 그래서 내포된 HTML DOM 요소가 삭제되기 전에 필요한 요소를 모두 옮길 필요가 있다. 이렇게 하기 위해 Dojo 위젯의 메서드 fillInTemplate() 을 재정의해야 한다. 이 메서드는 원래 HTML DOM 요소와 이미 생성된 Dojo 위젯을 모두 다룰 수 있게 해준다. 그 방법은 Listing 28에서 살펴보겠다(원래 상위 클래스의 fillInTemplate() 메서드를 호출해야 함을 명심하라).

Listing 28. dojoAjax/src/widget/HelloWorld.js: 정적 내포 HTML 전송하기

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templateString: '<div dojoAttachPoint="domNode"></div>',

// override

fillInTemplate: function(args, frag) {

// Getting original HTML element

var source = this.getFragNodeRef(frag);

// Moving all children of original element to

// the desired node of the new component

while(source.hasChildNodes()) {

var node = dojo.dom.removeNode(source.firstChild);

this.domNode.appendChild(node);

}

// Invoking original dojo fillInTemplate() method

dojo.widget.HelloWorld.superclass.fillInTemplate.call(this, args, frag);

}

});

그래서 위 코드는 모든 HTML DOM 노드를 원하는 곳에 내포 HTML로 옮긴다. 이 경우에 domNode 결합점의 자식이 된다. HTML 템플릿은 문자열로 제공된다.

정적 내포 HTML을 다루는 또 다른 방법은 위젯 속성 isContainer를 true로 설정하는 것이다. 이것은 Listing 28의 방법처럼 HTML 내용을 옮겨야 한다.

내포 HTML 동적으로 추가하기

동적으로 내포 HTML을 추가하는 방법은 두 가지가 있다. 이 방법은 동적 HTML이 어떻게 제공되느냐에 따라 다르다.

문자열로 제공되는 경우에는 원하는 DOM 노드의 innerHTML 속성을 이용해 새 HTML을 설정할 수 있다.

DOM 노드로 제공되는 경우에는 원하는 DOM 노드의 appendChild() DOM 메서드를 이용하여 추가할 수 있다.

두 가지 모두 적당한 예는 다음과 같다.

Listing 29. dojoAjax/src/widget/HelloWorld.js: 내포 HTML 동적으로 추가하기

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templatePath: '<div dojoAttachPoint="domNode"></div>',

// dynamic setters

setHtml: function(html) {

if (dojo.lang.isString(html)) {

this.domNode.innerHTML = html;

} else if (dojo.dom.isNode(html)) {

// Cleaning whatever was there before

dojo.dom.removeChildren(this.domNode);

// Adding new element

this.domNode.appendChild(html);

} else {

dojo.lang.assert(false, "setHtml called with incorrect type: "

+ (typeof html));

}

}

});

내포 위젯

이 절에서는 사용자 특화된 내포 위젯을 다루는 기법을 소개한다.

정적 내포 위젯

위젯 속에 위젯을 사용하는 경우가 있다. Dojo TabContainer와 Tree 위젯은 좋은 예다.

Listing 30 은 내포 Button 위젯을 HelloWorld 위젯 안에 사용하는 경우다.

Listing 30. test.html: 정적 내포 위젯 예제

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

dojo.require("dojo.widget.Button");

</script>

</head>

<body>

<div dojoType="HelloWorld"><div dojoType="Button"></div></div>

</body>

</html>

이 가장 간단한 예제에서 isContainer 위젯 매개변수는 참으로 정의하고 HTML 템플릿 안에 containerNode 결합점을 정의해야 한다. 그거면 끝이다. 내포 위젯은 자동으로 그려지고 containerNode에 추가된다.

Listing 31. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

isContainer: true,

templateString: '<div><div dojoAttachPoint="containerNode">'

+ '</div></div>'

});

위 해법은 기본 Dojo 동작만 쓰기 때문에 단순하다. 원한다면 더 복잡하게 사용할 수 있지만 postCreate() 메서드에서 자식 배열(모든 정적 내포 위젯을 담을 표준 위젯 필드)를 처리해야 한다.

Listing 32에서 내포된 사용자 정의 위젯을 containerNode에 추가할 수 있을 뿐만 아니라 내포 위젯 타입 목록을 titleNode 결합점에 추가할 수도 있다.

Listing 32. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

isContainer: true,

templateString: '<div><div dojoAttachPoint="titleNode"></div>'

+ '<br/><div dojoAttachPoint="containerNode">'

+ '</div></div>',

postCreate: function() {

for(var i in this.children) {

this._addRow(this.children[i]);

}

},

_addRow: function(component) {

this.titleNode.appendChild(

document.createTextNode(component.widgetType));

this.titleNode.appendChild(

document.createElement("br"));

}

});

Listing 33은 Listing 32에 정의한 위젯이 동작하는 test.html이다.

Listing 33. test.html: 복수개의 정적 내포 위젯

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

dojo.require("dojo.widget.Button");

dojo.require("dojo.widget.ContentPane");

</script>

</head>

<body>

<div dojoType="HelloWorld">

<div dojoType="Button"></div>

<div dojoType="ContentPane"></div>

</div>

</body>

</html>

내포 위젯을 다루는 더 유용한 예를 찾으려면 Dojo 툴킷의 TabContainer와 Tree 위젯을 보라.

내포 위젯을 동적으로 추가하기

사용자가 런타임에 Dojo 위젯을 위젯에 프로그래밍적으로 추가하고 싶다고 가정해 보자.

위젯 속성과 그들의 동적 변경자에 대해 이야기한 걸 기억하는가? 두 가지 사이의 일관성이 구조적으로 강제 사항이 아닌 것이 현재 Dojo 위젯 구조의 흠일지도 모른다. 물론 이 방법은 더 유연하게 하며 그다지 심각하지 않다. 하지만 그 속성에 대해 동적 변경자가 있는 것을 모른다면 성가신 일이 될 수도 있다. 개발자들이 그것을 추가하는 것을 잊기도 하기 때문에 위젯의 사용성을 상당히 떨어뜨린다.

내포 위젯에도 동일한 문제가 있다. 정적인 방법 대신에 다른 동적인 방법으로 추가해야 한다. 동적으로 추가하기 위해 addChild() 메서드를 사용할 필요가 있다. Listing 34는 정적, 동적으로 위젯을 추가한다. 재사용을 위해 _addRow() 메서드로 분리된 부분에 주의하라. addChild() 메서드를 재정의할 때 상위 클래스도 호출해야 한다.

Listing 34. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

isContainer: true,

templateString: '<div><div dojoAttachPoint="titleNode"></div>'

+ '<br/><div dojoAttachPoint="containerNode">'

+ '</div></div>',

postCreate: function() {

// adding statically

for(var i in this.children) {

this._addRow(this.children[i]);

}

},

addChild: function(child, overrideContainerNode,

pos, ref, insertIndex) {

this._addRow(child);

dojo.widget.HelloWorld.superclass.addChild.call(

this, child, overrideContainerNode);

},

_addRow: function(component) {

this.titleNode.appendChild(

document.createTextNode(component.widgetType));

this.titleNode.appendChild(

document.createElement("br"));

}

});

Listing 35는 Button 위젯을 생성하고 동적으로 Listing 34의 위젯을 추가하는 것이다.

Listing 35. test.html: 내포 위젯을 동적으로 추가하기

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

dojo.require("dojo.widget.Button");

dojo.addOnLoad(function(){

var button = dojo.widget.createWidget("Button",

{caption: "Submit"});

dojo.widget.byId('someID').addChild(button);

});

</script>

</head>

<body>

<div id="someID" dojoType="HelloWorld"></div>

</body>

</html>

복합 위젯

위젯이 항상 또 다른 위젯을 포함하길 원할 수도 있다. 이 절에서는 이를 처리하는 두 가지 방법, 즉 프로그래밍적인 방법과 HTML 템플릿을 사용하는 방법을 다룬다.

* 용어에 대한 메모 : 내포 위젯과 복합 위젯에 대해 완벽하게 정의된 단어는 아직 없다. 이 튜토리얼을 위해 내가 사용하고 있는 의미는 다음과 같다.

- 내포 : 위젯이 외부의 다른 위젯을 자식으로 갖는 것이다. 내포된 HTML 요소나 addChild() 메서드를 사용한다. 이를테면 TabContainer 위젯은 ContentPane을 내포 위젯으로 담을 수 있다.

- 복합 : 내부적으로 자식 위젯으로 생성되는 위젯을 말한다. 대개 부모 위젯의 postCreate() 메서드를 사용한다.

복합 위젯을 프로그래밍적으로 정의하기

먼저 복합 위젯을 만들어 프로그래밍 접근을 하겠다 (이 접근 방법에 대해 더 알고 싶다면 참고 자료를 보라)

HelloWorld 위젯의 HTML 템플릿에서 새 위젯이 나타나기 원하는 결합점을 정의한다. 다음으로 위젯의 postCreate() 메서드에서 프로그래밍적으로 새 위젯을 만들고 노드에 추가한다.

복합 위젯은 (내포 위젯을 사용할 때와 같은) addChild() 메서드를 사용하여 주 위젯의 자식 목록을 추가해야 한다. 이렇게 함으로서 주 위젯과 함께 적절히 소멸하여 메모리가 새는 것을 막을 수 있다.

Listing 36은 프로그래밍적으로 Butoon 위젯을 만들고 그것을 주 위젯에 추가하는 것이다.

Listing 36. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.require("dojo.widget.Button"); // we require nested widget definition>

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

isContainer: true,

templateString: '<div>Hello World <br/> '

+ '<div dojoAttachPoint="compositeWidgetNode"></div></div>',

// override

postCreate: function(args, frag) {

this.btnSubmit = dojo.widget.createWidget("Button", { caption: "Submit" });

this.addChild(this.btnSubmit, this.compositeWidgetNode);

}

});

코드를 세부적으로 살펴보자.

먼저 dojo.require("dojo.widget.Button");을 호출해 요구된 위젯 정의의 참조를 포함한다.

다음으로 isContainer 속성을 true로 설정한다. 이 속성은 HtmlWidget 상위 클래스에서 온 것이다. 이 속성은 자식 위젯을 관리하기 위한 하부 구조로 addChild()와 removeChild() 메서드를 제공하며 부모 위젯의 크기가 바뀌었을 때 onResized() 를 호출한다.

HTML 템플릿(파일 또는 문자열)은 새 자식 위젯이 추가될 곳에 노드를 정의할 수 있다. 기본 명칭은 containerNode이다. 결합점을 (예제에서처럼) 다른 이름으로 하고 싶다면 addChild() 호출시 두 번째 인자를 명시해야 한다. 특히 복합 위젯에 노드가 하나만 있다면 일관성 있게 containerNode를 쓰도록 한다.

다음으로 복합 위젯을 생성하기 위해 dojo.widget.createWidget()를 사용하고 this.addChild()로 추가한다.

물론 addChild() 대신에 this.nestedWidgetNode.appendChild(this.btnSubmit.domNode);. 를 사용할 수 있다. 그러나 이 경우에는 새 위젯이 부모 위젯의 자식으로 추가되지 않고 부모가 소멸할 때 수동으로 제거해야 한다. 새 위젯은 크기 변경에 대한 통보와 같은 부모 자식 관계의 이점을 잃어버린다. 대부분의 경우 제공되는 기반구조를 쓰는 것이 나으므로 해킹(hack)은 마지막 선택으로 남겨두라.

Listing 37은 Listing 36의 위젯을 테스트하는 test.html 파일이다.

Listing 37. test.html: 복합 위젯 테스트

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body>

<div dojoType="HelloWorld">

</div>

</body>

</html>

HTML 템플릿에서 복합 위젯 정의하기

복합 위젯을 만드는 다른 방법은 HTML 템플릿에 직접 정의하는 것이다. 이 방법은 적절하며 Dojo 0.4에서는 더 직접적인 방법을 제공할 것이다. 아래의 코드 예제는 이전 코드보다 커 보인다. 하지만 복합적인 문제에서 더 간단해 보이고 더 적은 자바스크립트 루틴이 필요할 것이다.

Listing 38은 HTML 템플릿에 정의된 복합 위젯을 처리하는 위젯 코드다. 이 방법은 현재로선 약간의 Dojo 마법을 사용해야 한다. Listing 37의 test.html을 사용해 이 위젯을 테스트한다.

Listing 38. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.require("dojo.widget.Button"); // we require nested widget definition

dojo.require("dojo.widget.*"); // useful libraries

dojo.require("dojo.xml.Parse");

dojo.require("dojo.dom");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

widgetType: "HelloWorld",

isContainer: true,

templateString: '<div>Hello World <br/> '

+ '<div dojoType="Button" caption="Submit">'

+ '</div></div>',

// override

postCreate: function(args, frag) {

// dojo mambo-jumbo that converts all dojo tags into widgets

var xmlParser = new dojo.xml.Parse();

var dojoParser = dojo.widget.getParser();

var jsObj = xmlParser.parseElement(this.domNode, null, true);

var components = dojoParser.createComponents(jsObj, this);

// now, 'components' is an array with all

// first-level composite dojo widgets

this.btnSubmit = components[0];

}

});

postCreate() 메서드에서는 위젯이 HTML 템플릿에서 이미 생성됐을 때 Dojo 파서를 실행하여 Dojo 정의를 전부 위젯으로 바꿔야 한다. 그 결과 첫 번째 레벨 위젯의 배열을 얻게 된다.

배열 속 위젯들은 HTML 템플릿과 순서가 같다. 복합 위젯의 자식 위젯에 접근하기 위해 someWidget.children[0] 을 사용하라.

* Dojo 0.4와 복합 위젯 : Dojo 0.4에서는 HTML 템플릿 내에 widgetsInTemplate 속성으로 복합 위젯을 정의하는 새 방법이 도입된다. 이 기능은 이 튜토리얼의 범위에서 벗어난다.

생성된 위젯을 얻는 다른 방법은 위젯에 유일한 ID를 발급하는 것이다. 그 후 위젯 id를 통해 얻으면 된다(dojo.widget.byId("...")). 이 방법을 사용할 때 (한 페이지에 한 위젯의 여러 인스턴스가 있다면) 그 id가 유일하도록 주의해야 한다. 그래서 이 방법이 더 큰 작업처럼 보인다. HTML 템플릿에는 이미 많은 id가 있다. 이 방법의 장점은 HTML 템플릿이 어떤 순서로 재배열되어도 문제없이 작동된다는 것이다.

두 경우 모두 복합 위젯은 createComponents() 메서드를 사용하여 루트 위젯의 자식으로 알맞게 추가된다.

Dojo 이벤트 다루기

이 절에서는 "Dojo 방식"으로 이벤트를 다루겠다. 이 장을 읽기 전에 참고자료의 Dojo event system을 읽어두면 좋을 것이다.

HTML 템플릿에 이벤트 핸들러를 붙이기

Listing 39는 Dojo 이벤트 시스템을 이용하여 Dojo 위젯의 이벤트를 다루는 방법이다. HTML 템플릿에서 dojoAttachEvent="eventName: eventHandlerMethod;" 속성을 정의해야 한다. eventName은 표준 DOM 이벤트 이름이다("onClidk" 같은). eventHandlerMethod는 위젯의 자바스크립트 코드에 정의된 메서드로 이벤트 발생시 호출된다. 이 메서드는 Dojo 이벤트 객체를 받아들인다.

Listing 39는 dojoAttachEvent 속성이 HTML 템플릿에서 어떻게 이용되는지 보여준다.

Listing 39. dojoAjax/src/widget/template/HtmlHelloWorld.html

<div>

<span dojoAttachEvent="onClick: onClickHandler;">

Click me

</span>

</div>

Listing 40 은 자바스크립트 코드에 onClickHandler() 이벤트 핸들러가 어떻게 정의되어 있는지 보여준다.

Listing 40. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlHelloWorld.html"),

onClickHandler: function(evt) {

alert("Node clicked");

}

});

Listing 41 은 Listing 39 와 40에서 정의한 위젯을 테스트하는 test.html 파일이다.

Listing 41. test.html: 이벤트 핸들링 테스트

<html>

<head>

<script type="text/javascript" src="dojoAjax/dojo.js"></script>

<script type="text/javascript">

dojo.require("dojo.widget.HelloWorld");

</script>

</head>

<body>

<div dojoType="HelloWorld">

</div>

</body>

</html>

Dojo 식으로 이벤트를 핸들링하는 것은 표준 DOM 이벤트를 사용하는 것(node.onclick = function(evt) { this.className='clicked';};}; 같은)과는 조금 다르다. 한 예로 목표 노드를 this 키워드를 통해 접근할 수 없고 대신에 Dojo의 evt.currentTarget 속성을 사용해야 한다.

또 다른 예로는 이벤트 핸들러로부터 true/false를 얻고 싶다면 Dojo로부터 얻은 객체를 사용해야 함을 들 수 있다. evt.returnValue = true/false;를 사용하라.

또 다른 흥미로운 점은 부모 DOM 노드의 이벤트가 넘쳐 자식에게 온 경우 이벤트를 멈출 수 있다는 것이다. dojo.event.browser.stopEvent(evt); 메서드를 사용하라.

게다가 Dojo는 세미콜론(;)을 이용하여 복수개의 이벤트 핸들러를 명시할 수 있다. 이를테면 다음과 같다. dojoAttachEvent="onClick: onClickHandler; onKeyPress: onKeyPressHandler;".

이벤트 핸들러를 동적으로 붙이기

어디든 자바스크립트로 이벤트 핸들러를 동적으로 붙일 수 있다. Listing 42에서는 postCreate 메서드에서 HelloWorld 위젯의 domNode DOM 요소를 이벤트 핸들러로 붙이고 있다. 이 위젯을 테스트하려면 Listing 41의 test.html을 사용하라.

Listing 42. dojoAjax/src/widget/HelloWorld.js

dojo.provide("dojo.widget.HelloWorld");

dojo.require("dojo.widget.HtmlWidget");

dojo.require("dojo.event.*");

dojo.widget.defineWidget("dojo.widget.HelloWorld", dojo.widget.HtmlWidget, {

templateString: '<div dojoAttachPoint="domNode">Click here</div>',

postCreate: function() {

var controller = this;

dojo.event.kwConnect({

srcObj: this.domNode,

srcFunc: "onclick",

targetObj: controller

targetFunc: "onClickHandler",

once:true});

},

onClickHandler: function() {

alert("Node clicked");

}

});

오래된 형태의 DOM 자바스크립트 이벤트 핸들링

Dojo는 프레임워크가 아니라 툴킷이다. 그래서 필요할 때만 서브시스템으로 사용할 수 있다. 한 가지 예로 이벤트 핸들러를 오래된 DOM 형태의 자바스크립트 방식으로 this.domNode.onclick = function() {dojo.debug("Clicked");};처럼 정의할 수 있다. 무엇을 하고 있는지만 확실히 알고 있다면 오래된 형태의 이벤트 핸들링에 문제가 없다.

어떤 경우 위젯 기반구조나 이벤트 핸들링 같은 Dojo 서브시스템을 확장된 형태로 사용하면 응용 프로그램의 메모리가 넘치거나 반응이 느려질 수도 있다. 한번에 시각적인 컴포넌트를 많이 불러들인 특이한 경우에 특히 그렇다. Dojo 서브시스템과 브라우저 가상 머신에 부담을 주지 않도록 하는 것이 좋다.

오래된 형태의 이벤트 핸들링 기법은 브라우저의 자바스크립트 가상 머신이 다루기 더 쉬울 수도 있다. Dojo 이벤트 핸들링 시스템을 사용하면 개발자의 삶이 더 편해진다. 개인적인 판단과 상식으로 이 둘 사이의 균형을 잡을 필요가 있다.

HTML 템플릿의 자바스크립트

HTML 템플릿에서 자바스크립트를 사용하면서 경험하는 가장 큰 문제는 HTML 템플릿의 개념적인 일관성이 깨진다는 것이다. 하지만 그것이 무얼 하는지 정확히 이해한다면 여전히 할만하다. 다음 예제를 보자.

<div onclick="dojo.widget.byId('${this.widgetId}').onMouseClick();">Click me<div>

개발과 디버깅: 기타

이 튜토리얼의 마지막 절에서는 Dojo 위젯 개발과 디버깅을 위해 가장 대중적인 두 가지 브라우저를 셋업하는 법을 다루고 Dojo 위젯 디버깅 과정에서 발견할 몇 가지 문제를 살펴보겠다. 그리고 필자가 Dojo 툴킷을 이용해 HTML 위젯 개발을 처음 시도하면서 겪은 몇 가지 경험을 소개하면서 마무리하겠다.

브라우저와 개발 도구

- 모질라 파이어폭스

모질라 파이어폭스는 웹 응용 개발을 위한 최고의 브라우저로 인식되고 있다. 파이어폭스는 쓸만한 자바스크립트 콘솔과 통합된 DOM 검사기(DOM Inspector)와 수 많은 플러그인을 갖추고 있다. 파이어버그(Firebug)와 웹 디벨로퍼 툴바(Web Developer Toolbar)는 가장 인기 있는 웹 개발 도구다.

파이어폭스 설치시 언제나 "수동" 설치를 선택하고 "개발 도구"를 선택하라. 그렇게 해야 자바스크립트 콘솔과 DOM 검사기가 설치된다.

파이어폭스와 관련된 기법도 흥미롭다. HTML 페이지에서 한 영역을 선택, 오른쪽 클릭을 하고 선택된 소스(View Selection Source)를 누르면 대부분의 경우 Dojo 위젯에서 실제로 생성한 HTML을 볼 수 있다. 이것은 매우 유용한 기능이다. 파이어버그 플러그인도 HTML 렌더링을 잘 보여준다.

파이어폭스 관련 도구를 받고 싶으면 참고자료를 보라.

- 마이크로소프트 인터넷 익스플로러

마이크로소프트™ 인터넷 익스플로러™는 여전히 대중적인 브라우저이다. 그렇기 때문에 웹 애플리케이션을 인터넷 익스플로러에서도 테스트해야 한다. 어떤 사람들은 파이어폭스보다 마이크로소프트 스크립트 디버거(Script debugger)를 선호한다.

인터넷 익스플로러 관련 도구를 받길 원하면 참고자료를 보라.

Dojo 위젯 디버깅하기

Dojo 위젯이 있는 페이지를 실행할 때 두 위치에서 에러가 발생한다.

자바스크립트 콘솔(또는 인터넷 익스플로러의 팝업/스크립트 디버거)

Dojo 디버그 패널

이 두 가지 다 살펴보는 것이 매우 중요하다.

디버깅을 사용할 수 없다면 로깅이라도 해야 한다. Dojo 디버그 패널에 메시지를 추가하는 dojo.debug("..."); 함수는 매우 유용하다. 또한 dojo.debugShallow(object);와 dojo.debugDeep(object); 함수를 자바스크립트 객체를 덤프하기 위해 사용할 수 있다.

만약에 오래된 파일(*.js나 *.css)이 캐시되어 문제가 발생한다고 생각하면 브라우저 캐시를 비우고(웹 디벨로퍼 툴바를 쓰면 더 빨리 할 수 있다) Ctrl 키를 누른 상태에서 페이지를 새로고침 버튼을 클릭하라(이론적으로는 Ctrl키와 함께 새로고침을 누르면 되어야 하지만 가끔은 그렇지 않을 때도 있다). 어떤 사람들은 브라우저 캐시 크기를 0으로 설정해 어떤 것도 캐시하지 못하게 한다. 이렇게 하면 파일 캐시만 막고 메모리 캐시는 막지 못하는 경우도 있다는 것을 명심하라. Ctrl+새로고침은 그런 경우 도움이 된다. 메모리 누수가 심각한 경우도 있다(윈도우에서는 작업 관리자(Task Manager)로 추적할 수 있다). 그런 경우에는 브라우저를 완전히 재시작하는 것이 최상의 방법이다.

Dojo 위젯 디버깅에 대해 더 알고 싶으면 참고자료를 보라.

개인적인 경험들

Dojo 툴킷을 사용하며 경험했던 문제들을 소개하려 한다. 내 가정은 브라우저 기반 자바스크립트를 사용했던 이전 경험에 바탕을 두었다. 어떤 경험은 나에게만 문제였을지도 모른다.

- 공통적인 에러와 해결책

경험했던 문제	해결책
위젯을 정의하기 위해 사용한 DOM 노드의 속성이 사라진 것 같다(id. style).	필요한 속성들은 예약하라. 오래된 형태의 자바스크립트 방법으로 위젯 접근하기와 내포 HTML을 보라.
"this.domNode"의 의미는 무엇인가?	this.domNode는 HTML 템플릿의 루트 DOM 요소의 기본 결합점이다.
위젯 생성시 변경자 메서드가 호출되나?	아니다. postCreate()가 요소에 직접 동작한다. 더 자세한 내용은 Widget attributes을 참고하라.
왜 속성은 위젯 생성시 전달되지 않을까?	위젯 자바스크립트 코드는 기본값을 가지고 정의되지 않기 때문이다.
<body onload="..."가 더 이상 작동하지 않는다.	대신에 Dojo 이벤트 시스템을 사용하라. 더 자세한 내용은 오래된 형태의 자바스크립트 방법을 참고하라.
내 CSS 스타일이 뒤죽박죽됐다.	CSS 클래스 이름은 전체 프로젝트에서 유일해야 하고 Dojo CSS 클래스 이름을 침범하지 말아야 한다.
dojo.byId() 와 dojo.widget.byId()의 차이점이 무엇인가?	dojo.byId()는 document.getElementById()의 별칭이고 dojo.widget.byId()는 dojo.widget.manager.getWidgetById()의 별칭이다.
dojo.require() 문장을 주석 처리했는데도 여전히 작동한다.	Dojo는 정규식을 사용하고 있다. 이것은 중요한 문제는 아니다.

정리

자바스크립트로 견고하고 안정적이며 고품질의 소프트웨어를 개발하는 것은 다른 프로그래밍 언어에서 하는 것과 원리가 비슷하다. 최고의 방법, 검증된 디자인 패턴, 상식을 사용하여 개발한다면 프로젝트는 성공적일 것이다.

* 더 공부하기 : 만약 Dojo 위젯 개발에 더 많은 정보가 필요하다면 지금이 바로 기존 Dojo 위젯 코드를 공부할 때다. 여러분은 이미 중요한 개념에 익숙해졌다. 또한 참고자료에서 Dojo 툴킷에 대한 글과 문서를 참고하라.

자바스크립트의 동적인 특성은 다른 언어보다 다루기 힘들다. 예를 들어 자바 언어는 강한 타입에, 네임스페이스(패키지)를 사용해야만 하고, Gang of Four의 디자인 패턴을 보는 듯한 런타임 라이브러리가 있다. 게다가 Javadoc 문서는 매우 유용하다. 이런 요소는 신규 개발자에게 매우 유리하고 바퀴의 재발명에서 벗어나 올바른 시작을 하게 한다.

자바스크립트의 경우엔 다르다. 이 언어는 유연하다. 가끔은 너무 유연하다. 자바스크립트로 많은 일을 할 수 있고 많은 방법을 사용할 수 있다. 하지만 잠시 지나서 본다면 코드는 누가 관리할까? 여러분이 너무 창의적이거나 자바스크립트 코드에 부주의하다면 무슨 말인지 알 것이다. 시간이 지나면 코드 저자에게도 유지보수가 매우 힘들어진다. 자바스크립트는 자바에 비해 너그롭지 못하다

그럼 무엇을 해야 할까? 코딩 표준을 이용하여 좋은 습관을 강제하는 것도 한 아이디어다. 자바 방식 코딩을 사용할 수도 있다. 몇 가지만 결정해 진짜 문제를 단순하게 만들어 신입 개발자들을 도울 수 있다.

패키지 사용을 위해 Dojo의 기반구조를 활용한다.

파일 하나에 하나의 클래스를 정의하고 클래스와 파일명을 일관성 있게 관리한다.

인자가 적합한 형을 가지는지 검증하고 public 메서드의 상단에 null이 없는 조건을 명시한다.

자바에서처럼 예외를 사용하고 파이어버그 플러그인의 스택을 추적한다.

dojo.declare()를 이용하여 클래스를 선언하고 상속을 위해 Dojo 기반구조를 사용한다.

다른 한편으로 보면 자바스크립트의 강력한 유연성을 기피하면 진정한 아름다움과 가치 있는 설계를 하지 못할 수도 있다. 여러분은 이런 일을 바라지는 않을 것이다. 그렇기 때문에 양 극단 사이에서 완벽한 균형을 찾을 필요가 있다.

- 기사의 원문보기 : Develop HTML widgets with Dojo

참고자료

교육

Dojo widgets FAQ: Dojo 뉴스그룹에 기반을 둔 Dojo HTML 위젯의 공통 질문을 찾을 수 있다.

The Dojo Event System: 이 문서 역시 알렉스 러셀이 적은 것으로 Dojo 이벤트 시스템에 대한 좋은 튜토리얼이다. dojo.event.*의 도구와 이벤트를 넓은 범위에서 조망한다.

The Dojo Project's JotSpot wiki: Dojo FAQ 홈페이지에 들어가 using JavaScript in a namespace outside Dojo ; creating composite widgets; 그리고 debugging Dojo에 대한 질문의 답을 찾아보라.

한국 developerWorks 웹 개발 존: 다운로드, 제품의 특성, 오픈 소스 프로젝트, 기술 자료, 트레이닝, 이벤트 알림, 웹 아키텍처, 개발 등의 특성화된 정보로 업무를 향상시킬 수 있다.

developerWorks technical events and webcasts: 학습 곡선을 줄이기 위해 기술 세션을 이용할 수 있다. 여기에서 대다수의 어려운 소프트웨어 프로젝트의 질과 결과를 향상시킬 수 있다.

제품 및 기술 얻기

Dojo 홈페이지: Dojo 툴킷을 받을 수 있다.

모질라 파이어폭스: 파이어폭스에서 웹 개발에 유용한 플러그인을 사용해 보라.

파이어폭스 파이어버그 플러그인: 예외 스택 추적, 디버깅, DOM 추적기를 포함한 자바스크립트 개발 플러그인을 다운받으라.

Firefox Web Developer toolbar: 자바스크립트 개발에 유용한 많은 도구를 받을 수 있다.

Venkman, the JavaScript debugger:파이어폭스 자바스크립트 디버깅 도구를 받으라.

인터넷 익스플로러: 인터넷 익스플로러에서 웹 개발에 유용한 플러그인을 확인하라.

Internet Explorer developers toolbar: 자바스크립트 개발에 유용한 도구를 경험할 수 있다.

Internet Explorer 5.0 Web Developer Accessories: 다운로드한 후 이 튜토리얼에서 이야기한 특성들에 대한 테스트를 시도해보라(인터넷 익스플로서 6에서 수정된 부분은 "Powering up with Internet Explorer Extensibility"에서 확인할 수 있다).

Internet Explorer Microsoft Script Debugger: 인터넷 익스플로러 자체를 다운로드하고 이 툴을 설치하여 이용하라.

IBM 시험판 소프트웨어: 한국 developerWorlds에서 직접 다운로드해 다음 개발 프로젝트에 사용할 수 있다.

토론

developerWorks Community: 개발자를 위해 혹은 개발자에 의해 운영되는 블로그, 포럼 등을 방문해보라.

developerWorks blogs: developerWorks 커뮤니티에 참여해 보라.

필자소개

Igor Kusakov는 10년 경험의 IT 전문가로 1990년대 말부터 웹과 분산 응용 프로그램 개발을 해왔다. 이고르는 현재 IBM Rational의 컨설턴트로 Ajax Dojo 기반의 애플리케이션 개발을 이끌고 있다. 이고르의 첫 번째 직업적 흥미는 자바 개발, 웹 프로젝트 아키텍처, 리치 자바스크립트 기반 브라우저 클라이언트, 현대적인 지속성 프레임워크, 효과적인 개발을 위한 도구다. 컴퓨터 과학을 공부하면서 이고르는 자바, C++, C 프로그래밍을 이수했다