Ext JS - Learning Center

Tutorial:Extending Ext Class (Korean)

From Learn About the Ext JavaScript Library

Revision as of 02:44, 21 April 2009 by Michellek (Talk | contribs)
(diff) ← Older revision | Current revision (diff) | Newer revision → (diff)
Jump to: navigation, search


Summary: Ext 클래스를 확장하는 데 필요한 단계를 살펴봅니다.
Author: Jozef Sakalos (번역:윤재홍)
Published: September 3, 2007
Ext Version: 1.1+ / 2.0+
Languages: en.png English cn.png Chinese kr.png Korean

br.png Portuguese

Contents

목표

Intended resulting IconCombo

텍스트 앞에 아이콘을 보여주는 Ext.form.Combobox 확장 클래스를 만들어봅시다. 예를 들자면, 이런 콤보박스는 국가 선택을 할 때 나라 이름 앞에 국기를 보여주는 경우에 유용할 겁니다.

우리 확장 클래스에게 Ext.ux.IconCombo라는 이름을 지어줍시다.

파일 만들기

첫번째 단계는 개발 과정에 필요할 파일을 준비하는 겁니다. 아마 이런 파일들을 필요로 할겁니다.

  • iconcombo.html: 우리의 새로운 확장 클래스를 이용할 어플리케이션을 위한 HTML 파일
  • iconcombo.js: 어플리케이션의 자바스크립트 코드
  • Ext.ux.IconCombo.js: 확장 클래스의 자바스크립트 파일
  • Ext.ux.IconCombo.css: 확장 클래스의 스타일시트

iconcombo.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css">
    <link rel="stylesheet" type="text/css" href="Ext.ux.IconCombo.css">
    <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="../extjs/ext-all-debug.js"></script>
    <script type="text/javascript" src="Ext.ux.IconCombo.js"></script>
    <script type="text/javascript" src="iconcombo.js"></script>
    <!-- A Localization Script File comes here -->
    <script type="text/javascript">Ext.onReady(iconcombo.init, iconcombo);</script>
    <title>Ext.ux.IconCombo Tutorial</title>
</head>
<body>
<div style="position:relative;width:300px;top:24px;left:64px;font-size:11px">
    <div>Icon combo:</div>
    <div id="combo-ct"></div>
</div>
</body>
</html>

이 HTML은 Application Layout for Beginners 튜토리얼에서 소개된 부분에서 가져와서 조금 수정했습니다.

iconcombo.js

/**
  * Ext.ux.IconCombo Tutorial
  * by Jozef Sakalos, aka Saki
  * http://extjs.com/learn/Tutorial:Extending_Ext_Class
  */
 
// reference local blank image
Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif';
 
// create application
iconcombo = function() {
 
    // public space
    return {
        // public properties, e.g. strings to translate
 
        // public methods
        init: function() {
            var icnCombo = new Ext.ux.IconCombo({
                store: new Ext.data.SimpleStore({
                    fields: ['countryCode', 'countryName', 'countryFlag'],
                    data: [
                        ['US', 'United States', 'x-flag-us'],
                        ['DE', 'Germany', 'x-flag-de'],
                        ['FR', 'France', 'x-flag-fr']
                    ]
                }),
                valueField: 'countryCode',
                displayField: 'countryName',
                iconClsField: 'countryFlag',
                triggerAction: 'all',
                mode: 'local',
                width: 160
            });
            icnCombo.render('combo-ct');
            icnCombo.setValue('DE');
        }
    };
}(); // end of app
 
// end of file

이 파일에서는 갖고 놀면서 우리의 확장 클래스를 테스트하기 위한 하나의 IconCombo 클래스를 하나 생성했습니다.

Ext.ux.IconCombo.js

// Create user extensions namespace (Ext.ux)
Ext.namespace('Ext.ux');
 
/**
  * Ext.ux.IconCombo Extension Class
  *
  * @author Jozef Sakalos, aka Saki
  * @version 1.0
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  * @constructor
  * @param {Object} config Configuration options
  */
Ext.ux.IconCombo = function(config) {
 
    // call parent constructor
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
 
}; // end of Ext.ux.IconCombo constructor
 
// extend
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
}); // end of extend
 
// end of file

이 파일에서 우리가 한 것이라고는 단지 Ext.form.ComboBox의 기능만을 갖고 있는 껍데기 확장 클래스를 만든 것 뿐입니다. 하지만, 지금 단계에서는 단지 작업할 수 있는 시작점을 필요로 하기에 이걸로 충분합니다.

Ext.ux.IconCombo.css

.x-flag-us {
    background-image: url(../img/flags/us.png) !important;
}
.x-flag-de {
    background-image: url(../img/flags/de.png) !important;
}
.x-flag-fr {
    background-image: url(../img/flags/fr.png) !important;
}

여러분의 경로는 국기 아이콘들을 어디에 저장했는지에 따라 다를겁니다. 국기 아이콘들은 famfamfam.com에서 다운로드 받으시면 됩니다.

시작해볼까요?

현재까지 아주 좋습니다. 인터넷 브라우져로 iconcombo.html을 열어보면, 여러분은 아마 한개의 일반적인 콤보박스를 보게 될 겁니다. 이 콤보박스는 세개의 아이템을 갖고 있고 독일이 선택되어 있을겁니다. 맞지요? 물론, 아직 아이콘은 없지요...

자 이제 작업을 시작해볼까요. 다음 코드를 Ext.ux.IconCombo.js 파일에 추가하시는데, 부모 생성자 호출부분 바로 다음에 추가하세요.

this.tpl = config.tpl ||
      '<tpl for="."><div class="x-combo-list-item">'
    + '<table><tbody><tr>'
    + '<td>'
    + '<div class="{' + this.iconClsField + '} x-icon-combo-icon"></div></td>'
    + '<td>{' + this.displayField + '}</td>'
    + '</tr></tbody></table>'
    + '</div></tpl>'
;

여기서는 기본 콤보박스 아이템 템플릿을 iconClsField를 이용하는 우리의 템플릿으로 오버라이드 했습니다.

이제는 다음 내용을 Ext.ux.IconCombo.css 파일에 추가하세요.

.x-icon-combo-icon {
    background-repeat: no-repeat;
    background-position: 0 50%;
    width: 18px;
    height: 14px;
}

좋군요. 다음 테스트를 위한 준비가 되었으니 브라우져에 있는 페이지를 다시 불러보시죠. 멋지지 않습니까?

리스트가 펼쳐졌을 때 멋진 아이콘들을 갖게 되었는데, 이게 접혔을 때도 국기가 보이게 하고 싶군요. 여러분도 그렇지요?

그럼 다음 코드를 생성자에 있는 템플릿 생성 부분 뒤에 넣어보세요.

this.on({
    render:{scope:this, fn:function() {
        var wrap = this.el.up('div.x-form-field-wrap');
        this.wrap.applyStyles({position:'relative'});
        this.el.addClass('x-icon-combo-input');
        this.flag = Ext.DomHelper.append(wrap, {
            tag: 'div', style:'position:absolute'
        });
    }}
});

이 코드는 render 이벤트 리스너를 추가하는 겁니다. 이 리스너는 엘리멘트들에 스타일을 적용하고 국기를 위한 div 콘테이너를 추가합니다.

그리고, 다음 내용을 extend 부분에 추가합니다. 그럼 이렇게 되겠지요.

// extend
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
    setIconCls: function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    },
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }
 
}); // end of extend

우리는 setIconCls 함수를 추가하고 setValue 함수를 오버라이드했습니다. 당연히, 우리는 원래의 setValue 함수가 제 역할을 하기를 원하기 때문에, 먼저 부모의 setValue 함수를 호출하고 나서 우리가 만든 setIconCls 함수를 호출합니다.

다음 내용을 여러분의 Ext.ux.IconCombo.css 파일에 추가하세요.

.x-icon-combo-input {
    padding-left: 26px;
}
.x-form-field-wrap .x-icon-combo-icon {
    top: 3px;
    left: 6px;
}

드디어 마지막

자 이제 마지막 테스트입니다. HTML 페이지를 다시 불러보세요. 갖다 붙이는 데 실수만 하지 않았다면, 여러분은 이제 자신만의 새로운 Ext.ux.IconCombo 확장 클래스를 갖게 된 겁니다. 여러분이 여기까지 한 내용은 Ext 클래스를 확장하는 가장 기본적인 것들이었고, 여러분은 더 개선할 수 있을 것입니다.

Brian Moeskau 덕분에, 저는 Ext.ux.IconCombo를 간소화시켰고, 이제는 여러분의 어플리케이션에 사용될 수 있을 정도의 최종 버전이 되었다고 생각됩니다. 그 자바스크립트 코드와 css는 다음과 같습니다.

Ext.ux.IconCombo.js

// Create user extensions namespace (Ext.ux)
Ext.namespace('Ext.ux');
 
/**
  * Ext.ux.IconCombo Extension Class
  *
  * @author  Jozef Sakalos
  * @version 1.0
  *
  * @class Ext.ux.IconCombo
  * @extends Ext.form.ComboBox
  * @constructor
  * @param {Object} config Configuration options
  */
Ext.ux.IconCombo = function(config) {
 
    // call parent constructor
    Ext.ux.IconCombo.superclass.constructor.call(this, config);
 
    this.tpl = config.tpl ||
          '<div class="x-combo-list-item x-icon-combo-item {' 
        + this.iconClsField 
        + '}">{' 
        + this.displayField 
        + '}</div>'
    ;
 
    this.on({
        render:{scope:this, fn:function() {
            var wrap = this.el.up('div.x-form-field-wrap');
            this.wrap.applyStyles({position:'relative'});
            this.el.addClass('x-icon-combo-input');
            this.flag = Ext.DomHelper.append(wrap, {
                tag: 'div', style:'position:absolute'
            });
        }}
    });
} // end of Ext.ux.IconCombo constructor
 
// extend
Ext.extend(Ext.ux.IconCombo, Ext.form.ComboBox, {
 
    setIconCls: function() {
        var rec = this.store.query(this.valueField, this.getValue()).itemAt(0);
        if(rec) {
            this.flag.className = 'x-icon-combo-icon ' + rec.get(this.iconClsField);
        }
    },
 
    setValue: function(value) {
        Ext.ux.IconCombo.superclass.setValue.call(this, value);
        this.setIconCls();
    }
 
}); // end of extend
 
// end of file

Ext.ux.IconCombo.css

/* application specific styles */
.x-flag-us {
    background-image:url(../img/flags/us.png) !important;
}
.x-flag-de {
    background-image:url(../img/flags/de.png) !important;
}
.x-flag-fr {
    background-image:url(../img/flags/fr.png) !important;
}
 
/* Ext.ux.IconCombo mandatory styles */
.x-icon-combo-icon {
    background-repeat: no-repeat;
    background-position: 0 50%;
    width: 18px;
    height: 14px;
}
.x-icon-combo-input {
    padding-left: 25px;
}
.x-form-field-wrap .x-icon-combo-icon {
    top: 3px;
    left: 5px;
}
.x-icon-combo-item {
    background-repeat: no-repeat !important;
    background-position: 3px 50% !important;
    padding-left: 24px;
}