교육 및 세미나2016. 5. 23. 12:47

김앤곽 센차컨설팅그룹에서 6/18,6/25(16시간) ExtJS 개발자 및 Sencha 기술에 관심있는 분들을 위한 강좌를 진행합니다.
Sencha Ext JS의 기본 개념부터 실무 기술까지 배울수 있는 좋은 기회입니다. 또한 Sencha Architect를 통한 개발방법론과 다양한 샘플코드를 직접 구현해 봅니다. ExtJS를 처음 접하시는 분과 다양한 실무기술을 익히고 싶은 분께 적합합니다.


신청 : http://onoffmix.com/event/69103

'교육 및 세미나' 카테고리의 다른 글

Adobe Ria 세미나 참석  (0) 2011.01.10
Posted by 베니94
자바스크립트/Ext JS2016. 4. 30. 16:40

ExtJS Grid CRUD 프로그래밍 강좌입니다.


http://benneykwag.github.io/lecture/2016/04/13/grid-crud.html

Posted by 베니94
자바스크립트/Ext JS2016. 4. 15. 11:42

eui프레임웍은 다국어 및 메시지를 위한 처리가 적용되어 있습니다. 일반적인 다국어는 extjs가 사용하는 컴포넌트의 기본 메시지나 레이블을 의미하며 이러한 처리의 변경은 sdk내부의 여러 국가별 로케일 파일을 적용하여 해결합니다. eui프레임웍에서의 다국어는 Ajax통신을 통해 얻어온 메시지를 또는 레이블을 컴포넌트에 쉽게 적용할 수 있는 방법을 제시합니다.


강좌 확인은 아래 링크를 클릭하세요.


http://benneykwag.github.io/lecture/2016/04/07/%EB%8B%A4%EA%B5%AD%EC%96%B4%EC%B2%98%EB%A6%AC.html

Posted by 베니94
자바스크립트/Ext JS2014. 8. 18. 01:11

ExtJS 5 멀티테마와 로케일 설정 

 

이번 강의는 애플리케이션에 내에서 테마를 변경하는 방법과 다국어를 설정하는 방법에 대해 알아볼 것이다. ExtJS5는 총4개의 테마와 모바일용 touch용 까지 세분화해 총6개의 테마를 지원한다. 일반적으로 한개의 테마만 사용하여 시스템을 구축할 것이다. 그러나 때에 따라 테마를 변경하거나 모바일에서 접근할 경우를 대비 neptune-touch, crisp-touch테마로 전환할 필요가 있다. 

또한 한국어를 포함한 영어, 일어 등 애플리케이션 내부에서 언어를 선택할 수 있도록  다국어 지원 방법을 알아보도록 하자. 


 

 

이 강좌는 KitchenSink앱을 분석하고 분석 내용을 공유한다. 더 자세한 내용을 알고 싶다면 KitchenSink앱을 자세히 분석해 보길 바란다.  

 

이번 강좌는 아래 환경에 맞춰 진행한다. 

Sencha CMD : 5.0.1.231 

ExtJS : 5.0.1 

 

테스트용 App생성 

테스트용 앱을 생성할 것이다. 이를 위해 Sencha CMD가 필요하다. 버전5에 이르러 Sencha CMD는 시작과 끝을 이어주는 필수적인 도구로 사용된다.  

 

필자는 앱이 생성될 루트에 workspace를 생성하고 진행하였다. 이렇게 하면 모든 앱마다 존재하는 ext폴더는 workspace루트에 하나만 존재하고 이하 모든 앱이 이를 공유하는 형태로 개발되게 된다. 빌드의 결과물 또한 workspace/build 폴더에 저장된다.

 sencha app watch  사용할 경우 이 workspace가 웹루트로 작동  것이다. 

  

workspace를 생성하자. 

sencha generate workspace ./workspace 

 

생성된 workspace폴더로 이동하고 App을 생성하자. 

sencha generate app -ext KitchenSink ./kitchensink 

 

 

 

 

Manifest 지정하기 

 

아래 코드는 앱루트의 index.html 파일이다. 굵은 <script.. var Ext = Ext||로 시작하는 부분이 새로 추가한 부분이다. 

Ext.beforeLoad 함수를 구현하고 있다. 이 함수는  bootstrap.js파일 내부에서 호출되며 Microloader클래스 내부에서 앱실행에 필요한 로드과정 전에 Ext.beforeLoad함수가 존재하면 실행되도록 했다. 

 

<!DOCTYPE HTML> 

<html manifest=""> 

<head> 

    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 

    <meta charset="UTF-8"> 

    <title>KitchenSink</title> 

    <!-- The line below must be kept intact for Sencha Cmd to build your application --> 

    <script type="text/javascript"> 

        var Ext = Ext || {}; 

        Ext.repoDevMode = true; 

        Ext.beforeLoad = function(tags){ 

            var theme = location.href.match(/theme=([\w-]+)/), 

                    locale = location.href.match(/locale=([\w-]+)/); 

            theme  = (theme && theme[1]) || (tags.desktop ? 'crisp' : 'crisp-touch'); 

            locale = (locale && locale[1]) || 'en'; 

            Ext.manifest = theme + "-" + locale; 

            Ext.microloaderTags = tags; 

        }; 

    </script> 

    <script id="microloader" type="text/javascriptsrc="bootstrap.js"></script> 

</head> 

<body></body> 

</html> 


 
Ext.beforeLoad함수 내부에서 우리는 theme와 locale을 정하고 이를 Ext.manifest에 설정하고 있다앱에 대한 세부사항을 설정하는 app.json 파일은 Sencha CMD에 의해 런타임시 Ext.manifest에 전달하게 된다앱은 런타임시 이 manifest의 내용을 분석하여 앱실행에 관련된 모든 컨텐츠를 로딩하게 되는 것이다. 

app.json파일 수정 

이 파일은 앱에 대한 세부사항을 지정하는 파일이다. 이 파일은 Sencha CMD에 의해 생성되고 소비된다. 이 파일의 내용에 의해 Sencha CMD는 런타임에 사용할 Microloader내부의 Manifest에 전달한다. 

 

override설정 

app.json파일 내부의 override설정은 기본값이 ${app.dir}/override이다override는 app폴더내부 클래스를 재정의하여 클래스를 변경하고 적용할 수 있다다국어를 지원하기 위한 locale설정 또한 기존 클래스 변수의 내용을 재정의하는 것으로 가능한 것이다. 

 

override설정을 아래와 같이 변경하자. 

  "overrides": "${app.dir}/overrides,${app.dir}/locale/${app.locale}", 


 

아래 그림은 실제 적용 시 폴더구조의 모습이다. 

 

 

requires설정 

app.json내부 requires설정은 추가 패키지를 설정하고 다운로드 한다. 차트나 로케일 설정은 기본 패키지에 제외되어 있으므로 설정에 포함해야 한다. 

 "requires": [ 

    "ext-locale" 

], 


 

css설정 

 

기본 값은 "path":"bootstrap.css"일 것이다. 이 파일은 개발모드에서 테마파일의 위치를 알려주는 파일이다. 

 

 생성 후 최초의 모습은 아래와 같다. 

 

@import '../ext/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css'; 

 

패스를 잘 확인해 보자. workspace 아래 ext(sdk)폴더를 가리키고 있다. 이 파일은 sencha app watch명령이나 sencha app build명령에 의해 아래처럼 바뀔 수 있다. 

 

sencha app watch 

@import '../build/development/KitchenSink/resources/KitchenSink-all.css'; 

 

watch 모드가 작동하면 bootstrap.css파일 내부는 위와 같이 변경된다watch명령은 개발을 위한 pre build와 jetty서버를 지원한다. build 폴더의 위치는 workspace\build이고 개발 모드를 위한 development폴더 아래 해당 앱이름으로 폴더가 생성되게 된다. 

 

sencha app build 명령 이후 bootstrap.css 파일은 아래처럼 변경된다 

 

sencha app build 

@import '../build/production/KitchenSink/resources/KitchenSink-all.css'; 

 

workspace/build폴더 아래 배포를 위한 production 폴더가 생성되고 해당 앱이름으로 압축과 최적화를 마친 파일들이 위치하게 된다. 

 

다국어 지원을 위해 우리는 app.json내부 css설정을 변경해야 할 것이다. 일반적인 경우 이 설정을 변경할 필요가 없을 것이다. 그러나 다국어를 가능하게 할 경우 해당 언어별로 빌드가 여러 번 이루어져 실행되는 환경이기 때문이다.  

 

"css": [ 

    { 

        "path": "${build.out.css.dir}/KitchenSink-all.css", 

        "bootstrap": true 

    } 

], 


 

테마파일의 위치를 동적으로 변경하기 위해 변수처리했다build.out.css.dir변수는 해당 앱이 빌드 된 후 테마파일이 위치할 resources폴더를 의미한다. 

 

bootstrap설정 

 

bootstrap설정은 삭제하자. 이 설정은 bootstrap.json, boostrap.css파일 등을 생성하게 되는데 우리는 이 설정을 대체하는 설정을 추가할 것이다. 

 // 아래 주석처리할 것. 

/*"bootstrap": { 

    "base": "${app.dir}", 

    "manifest": "bootstrap.json", 

    "microloader": "bootstrap.js", 

    "css": "bootstrap.css" 

},*/ 

 

"manifest": { 

    "name": "${build.id}.json", 

    "bootstrap": "${build.id}.json" 

}, 


 

manifest설정은 각 테마와 로케일 별로 조합하여 생성하게 된다. 아직 구체적인 모습이 연상되지 않을 것이므로 $build.id변수에 의해 json파일이 여러 개 생성된다는 것만 알아 두자. 

 

output설정 

 

이 설정은 Sencha CMD의 3가지 output에 대한 위치를 지정한다. output은 production, development, testing으로 각각 배포, 개발, 테스팅의 용도로 파일이 생성된다. 기본 설정은 아래와 같다. 


"output": { 

    "base": "${workspace.build.dir}/${build.environment}/${app.name}" 

}, 


 

${workspace.build.dir}은 workspace/build이거나 workspace를 생성하지 않았다면 해당 앱 이하 build폴더를 의미한다. 

${build.enviroment}는 위에서 설명한 3가지 빌드 모드를 의미하며 실행명령에 따라 다음과 같이 달라질 것이다. 

 

sencha app watch     : workspace/build/development 

sencha app build        : workspace/build/production 

sencha app build -c testing : workspace/build/testing 


 

우리 의도에 맞도록 변경해야 한다. 핵심은 ${build.id}이다.   

"output": { 

    "base": "${workspace.build.dir}/${build.environment}/${app.name}/${build.id}", 

    "page": "../index.html", 

    "manifest": "../${build.id}.json", 

    "deltas": { 

        "enable": false 

    }, 

    "cache": { 

        "enable": false 

    } 

}, 


 

locale설정 

 

필요한 언어를 설정하자. 우리는 한국어와 영어를 지원하도록 설정하자. 

 "locales": [ 

    "en", 

    "ko" 

], 


 

builds 설정 

 여러 종류의 테마를 적용할 수 있다. 이 설정 내부의 테마는 locales설정과 함께 곱하기 하여 빌드된다. 

 "builds": { 

    "classic": { 

        "theme": "ext-theme-classic" 

    }, 

    "gray": { 

        "theme": "ext-theme-gray" 

    } 

    "crisp": { 

        "theme": "ext-theme-crisp" 

    }, 

    "crisp-touch": { 

        "theme": "ext-theme-crisp-touch" 

    }, 

    "neptune": { 

        "theme": "ext-theme-neptune" 

    }, 

    "neptune-touch": { 

        "theme": "ext-theme-neptune-touch" 

    } 

}, 


 

build.id는 위의 테마와 로케일을 모두 생성해 낸다아래 예를 참고하자. 

 1. classic-en 

 2. classic-ko 

 3. gray-en 

 4. gray-ko 

 5. crisp-en 

 6. crisp-ko 

 7. crisp-touch-en 

 8. crisp-touch-ko 

 9. neptune-en 

 10.  neptune-ko 

 11. neptune-touch-en 

 12.  neptune-touch-ko 


 

테마와 언어별로 각각 빌드를 생성한다면 2개의 언어 * 6개의 테마를 곱하여 총 12개의 빌드가 각기 생성될 것이다. 

 

소스코드 

 

설정을 마쳤으니 테마변경과 로케일 설정을 확인하기 위한 소스코드를 생성하자. 

이 클래스는 Main.js내부에 추가되고 테마와 언어를 변경할 수 있게 한다. 

 Ext.define('KitchenSink.view.Header', { 

    extend: 'Ext.Container', 

    xtype: 'appHeader', 

    id: 'app-header', 

    title: 'Ext JS Kitchen Sink', 

    height: 52, 

    layout: { 

        type: 'hbox', 

        align: 'middle' 

    }, 


    initComponent: function() { 

        document.title = this.title; 


        this.items = [{ 

            xtype: 'component', 

            id: 'app-header-logo' 

        },{ 

            xtype: 'component', 

            id: 'app-header-title', 

            html: this.title, 

            flex: 1 

        }]; 


        if (!Ext.getCmp('options-toolbar')) { 

            this.items.push({ 

                xtype: 'themeSwitcher' 

            }); 

        } 

        this.callParent(); 

    } 

}); 


 
Header클래스 내부에서 테마와 로케일을 설정하는 ThemeSwitcher클래스를 생성하자. 

 Ext.define('KitchenSink.view.ThemeSwitcher', function() { 

    var theme = location.href.match(/theme=([\w-]+)/), 

        locale = location.href.match(/locale=([\w-]+)/); 

 
 

    theme = (theme && theme[1]) || (Ext.microloaderTags.desktop ? 'crisp' : 'crisp-touch'); 

    locale = locale && locale[1] || 'en'; 

 
 

    if (!Ext.themeName && !!theme) { 

        var m = theme.match(/^([\w-]+)-(?:he)$/); 

        Ext.themeName = m ? m[1] : theme; 

    } 

 
 

    return { 

        extend: 'Ext.Container', 

        xtype: 'themeSwitcher', 

        id: 'theme-switcher-btn', 

        margin: '0 10 0 0', 

        layout: 'hbox', 

 
 

        initComponent: function() { 

            function setQueryParam(name, value) { 

                var query = Ext.Object.fromQueryString(location.search); 

                query[name] = value; 

                location.search = Ext.Object.toQueryString(query); 

            } 

 
 

            function makeItem(value, text, paramName) { 

                paramName = paramName || "theme"; 

 
 

                var checked = value === (paramName == "theme" ? theme : locale); 

 
 

                return { 

                    text: text, 

                    group: (paramName == 'theme' ? 'themegroup' : 'localegroup'), 

                    checked: checked, 

                    handler: function () { 

                        if (!checked) { 

                            if(paramName == 'theme') { 

                                setQueryParam('theme', value); 

                            } else { 

                                setQueryParam('locale', value); 

                            } 

                        } 

                    } 

                }; 

            } 

 
 

            var menu = new Ext.menu.Menu({ 

                    items: [ 

                        makeItem('neptune',       'Neptune'), 

                        makeItem('neptune-touch', 'Neptune Touch'), 

                        makeItem('crisp',         'Crisp'), 

                        makeItem('crisp-touch',   'Crisp Touch'), 

                        makeItem('classic',       'Classic'), 

                        makeItem('gray',          'Gray'), 

                        '-', 

                        makeItem('en',            'English',    'locale'), 

                        makeItem('ko',            '한국어',     'locale') 

                    ] 

                }); 

 
 

            this.items = [{ 

                    xtype: 'component', 

                    id: 'theme-switcher', 

                    cls: 'ks-theme-switcher', 

                    margin: '0 5 0 0', 

                    listeners: { 

                        scope: this, 

                        click: function (e) { 

                            menu.showBy(this); 

                        }, 

                        element: 'el' 

                    } 

                }]; 

 
 

            this.callParent(); 

        } 

    }; 

}); 


 
Main 클래스 내부에서 Header클래스를 호출하도록 수정한다.  

 Ext.define('KitchenSink.view.main.Main', { 

    extend: 'Ext.panel.Panel', 

    xtype: 'app-main', 

    requires: ['KitchenSink.view.Header'], 

    controller: 'main', 

    viewModel: { 

        type: 'main' 

    }, 

    layout: { 

        type: 'border' 

    }, 

    items: [{ 

        xtype: 'appHeader', 

        region : 'north' 

    },{ 

        region: 'center', 

        xtype: 'tabpanel', 

        items:[{ 

            title: 'Tab 1', 

            html: '<h2>Content appropriate for the current navigation.</h2>' 

        }] 

    }] 

}); 


 
index.html 내부에서 기본 테마와 로케일 설정은 crisp-en일 것이다물론 desktop일 경우를 예로 한다이후 ThemeSwitcher에 의해 언어를 영어에서 한글로 변경하면 한글로 전환 되는 것을 확인하기 위해 앱루트에 locale폴더를 생성하고 Header클래스를 아래와 같이 생성할 것이다. 이 클래스는 한글을 포함하고 있다. 

한글 지원 Header클래스의 위치는 /locale/ko/view/Header.js이다. 

 Ext.define('KitchenSink.locale.view.Header', { 

    override: 'KitchenSink.view.Header', 

    title: '안녕하세요 ^^' 

}); 


 

한가지 더 테스트 하자. 위의 Header클래스는 한글을 지원하기 위해 기존 app폴더의 Header클래스를 override하고 있다. 이것은 일반적인 override와 동일하므로 일반적인 override도 같이 테스트 하자. 

 

app.json설정을 통해 앱루트 아래 override폴더에 해당 클래스를 위치 시켜보자. 

/override/view/main/Main.js 

 Ext.define('KitchenSink.override.view.main.Main', { 

    override: 'KitchenSink.view.main.Main', 

    title: '오버라이드 테스트 KitchenSink.override.view.main.Main' 

}); 


 

이 클래스는 로케일 설정과 별개로 기존 Main클래스의 title설정을 대체 할 것이다.  

 

이제 Header클래스가 실행될 경우 필요한 css를 준비하자. ExtJS는 시스템에 css를 적용하기 위해 sass를 이용한다. 앱루트의 sass폴더에 각 클래스에 적용할 css를 sass형태로 코딩하여 추가하면 빌드시 테마에 적용될 것이다. 

 

/sass/src/view/Header.scss파일을 추가하자. 이 파일은 테마별로 다른 css스타일을 적용하는 코드다. 

 $kitchensink-header-background-color: #333; 

$kitchensink-header-text-color: #fff; 

$kitchensink-header-text-shadow-color: null; 

$kitchensink-header-use-gradient: true; 

 
 

@if $theme-name == 'ext-theme-neptune' or $theme-name == 'ext-theme-neptune-touch' { 

    $kitchensink-header-background-color: #81af34; 

    $kitchensink-header-text-shadow-color: #4e691f; 

} 

 
 

@if $theme-name == 'ext-theme-classic' or $theme-name == 'ext-theme-gray' { 

    $kitchensink-header-background-color: darken($base-color, 55%); 

} 

 
 

@if $theme-name == 'ext-theme-crisp' or $theme-name == 'ext-theme-crisp-touch' { 

    $kitchensink-header-background-color: #2a3f5d; 

    $kitchensink-header-use-gradient: false; 

} 

 
 

#app-header { 

    background-color: $kitchensink-header-background-color; 

    @if $kitchensink-header-use-gradient { 

        @include background-image(linear-gradient(top, lighten($kitchensink-header-background-color, 5), darken($kitchensink-header-background-color, 5))); 

    } 

border-bottom: 1px solid darken($kitchensink-header-background-color, 15); 

 
 

    @if $theme-name == 'ext-theme-neptune' { 

        .#{$prefix}nlg & { 

            background-image: url(images/header-bg.png); 

        } 

    } 

} 

 
 

#app-header-title { 

    padding: 15px 0 10px 0; 

 
 

    color: #fff; 

    font-size: 18px; 

    font-weight: bold; 

    @if $kitchensink-header-text-shadow-color != null { 

        text-shadow: 0 1px 0 $kitchensink-header-text-shadow-color; 

    } 

} 

 
 

#app-header-logo { 

    width: 40px; 

    height: 25px; 

 
 

    background: url(images/logo.png) no-repeat center 4px; 

} 

 
 

#theme-switcher-combo-labelEl { 

    color: $kitchensink-header-text-color; 

    font-weight: bold; 

} 

 
 

.ks-theme-switcher { 

    background-image: url(images/options.png); 

    width: 22px; 

    height: 22px; 

} 


 
위의 파일에서 로딩하는 각종 이미지 파일은 kitchenSink예제의 resources/images폴더를 복사하도록 하자. 

 

최종 폴더 구조는 그림과 같다. 


 

 

최종 빌드  

 

이제 마지막 빌드과정이 남았다. 해당 앱루트로 접근하고 sencha app build 명령을 수행하자. 위에서 언급했듯이 총6개의 테마와 2개의 언어가 모두 빌드되려면 총 12번의 빌드과정을 거치게 되어 상당한 시간이 소요될 것이다. 

 

 

빌드가 완료되면 workspace/kitchensink폴더 내부를 확인하자. 그림처럼 총 12개의 json파일이 테마와 로케일 설정별로 생성된 것이 보일 것이다. 이 총12개의 파일이 app.json의 설정에 의해 생성된 manifest이고 이 파일별로 테마와 언어가 다르게 실행되는 것이다. 


 

 

그렇다면 최종 빌드파일은 어떤 모습인지 확인해야 할 것이다. sencha app build명령은 production 빌드이므로 workspace/build/production/kitchensink폴더에 빌드파일을 저장했을 것이다. 

 


 

상당히 많은 량의 파일이 생성되었음을 볼  있다. 각 테마와 로케일 별로 총12개의 개별 빌드 폴더가 생성되어 독립적으로 실행가능 될 수 있다. 

 

완료된 결과를 브라우저를 통해 확인하자. 

workspace루트로 이동하여 sencha web start 명령을 실행하자. 


 

 

오른쪽 아이콘을 클릭해 언어를 한국어로 변경하면 기존 영문이 한글로 표시될 것이다. 


 

 

 

 

 

 

 


Posted by 베니94
자바스크립트/Ext JS2013. 10. 13. 15:08

오늘날 웹은 비약적인 발전을 이뤄, 이전에는 할 수 없었던 많은 일들이 웹상에서 가능하게 됐다. 웹의 패러다임이 변한만큼 기술도 서버에서 클라이언트로 중심이 이동했다. 이 정에서 자바스크립트 UI 프레임워크가 대세로 자리 잡은 게 현실이지만, 코드는 복잡해지고 유지보수와 확장성의 한계를 드러내게 됐다. 그런 점에서 개발 단계에만 초점이 맞춰진 여타 프레임워크에 비해 ExtJS는 유지보수와 향후 확장이 용이한 MVC 아키텍처를 제공하고 있다.

 

이번 시간에는 ExtJS의 MVC 패턴을 구현해 보고, MVC 패턴을 실무에서 어떻게 활용할 수 있는지 알아보자. 우선 ExtJS에서 사용하는 MVC 패턴을 살펴보겠다.

 

M : 모델(Model)을 지칭한다. ExtJS에서는 데이터를 표현하는 단위가 모델이다. 스토어(Store)가 필요로 하는 Grid, DataView, Form 등의 컴포넌트와 연결될 수 있다.

V : 뷰(View)는 데이터를 표현할 수 있는 모든 컴포넌트를 지칭한다. 모델을 통해 뷰는 데이터를 전달받아 이를 표현한다.

C : 컨트롤러(Controller) 뷰 사이에서의 통신을 처리한다. 컨트롤러는 뷰와 스토어를 참조할 수 있고, 자신이 관장하는 모든 뷰에서 발생하는 이벤트를 감시하며, 각 뷰에게 특정 처리에 대한 명령을 내리는 핵심적인 역할을 한다.

 

우리는 한 가지 내용을 더 알아야 한다. 바로 스토어다. 스토어는 모델들의 집합체로, 서버에서 통신 데이터를 가져오고, 이 데이터를 모델단위로 탑재해 Grid, DataView, Tree 등과 같은 컴포넌트에 전달한다.

이제 코드를 통해 MVC 패턴을 구현해 보자. ExtJS는 Sencha Cmd에서 애플리케이션을 생성하고 빌드할 수 있도록 지원한다.

 

개발환경 구축

개발환경 구축을 위해 Sencha Cmd와 ExtJS를 다운로드 받아 설치하고 환경을 세팅해보도록 하겠다.

아래 <그림 0-0>과 같이 Sencha사이트에 접속하여 좌측의 "Download"를 클릭하여 ExtJS를 다운받고 우측 하단의 "Sencha Cmd"를 클릭하면 <그림 0-1>과 같이 Sencha Cmd를 다운받는다.

<그림 0-0> extjs와 Sencha Cmd 다운로드 페이지

 

<그림 0-1> Sencha Cmd다운로드 페이지

 

이제 다운로드 받은 프로그램을 설치 하도록 하자. 참고로 자바가 먼저 설치되어 있어야 한다.

첫번째는 Sencha Cmd 설치파일을 실행하고 아래 <그림 0-2>에서 "Next"버튼을 클릭한다.

<그림 0-2> Sencha Cmd설치 화면1

 

아래 <그림 0-3>에서 "I accept the agreement"에 체크하고 "Next"버튼을 클릭하자.

<그림 0-3> Sencha Cmd설치 화면2

 

아래 <그림 0-4>에서 설치 폴더를 설정하고 "Next"버튼을 클릭한다.

<그림 0-4> Sencha Cmd설치 화면3

 

이후 계속 "Next"버튼을 클릭하면 설치과정이 진행되고 최종 "Finish"버튼을 클릭하면 Sencha Cmd 설치가 완료된다.

설치가 정상적인지 확인하기 위해 명령프롬프트 창을 열고 "sencha"명령을 실행해서 아래<그림 0-5>와 같이 나오면 설치가 잘 된것이다.

<그림 0-5> Sencha Cmd설치 확인화면

 

이 과정을 거쳤다면 C드라이브에 Sencha라는 폴더가 생성되었고 안으로 들어가면 Cmd폴더에 Sencha Cmd가 설치 되었을 것이다. 이제 다운로드한 Extjs4 라이브러리를 압축을 해제하고 C:\Sencha폴더 아래에 옮기도록 한다.

<그림 0-6> 설치 이후 폴더구조

이제 테마컴파일을 위해 루비를 설치하자. 아래 사이트에 접속하여 루비 Ruby 1.9.3-p448를 내려받고 설치하자.

http://rubyinstaller.org/downloads/

Sencha Cmd에서는 1.8또는 1.9버전만 지원한다. 꼭 1.9버전을 설치하자.

다음으로는 <그림 0-7>과 같이 빌드 과정에서 테마를 위한 sass컴파일용 compass를 설치하자.

 

<그림 0-7> compass 설치과정

  혹여 윈도우 7에 경우 정상적으로 설치 되지 않는 경우가 있는데 이때는 아래 사이트를 참고하여 수동으로 compass를 설치할 수 있다. 

http://awordpress.net/install-sass-compass-manually-windows/


애플리케이션 생성

아래 명령을 실행하여 MyMvc라는 애플리케이션을 생성하자.

sencha -sdk C:\Sencha\ext-4.2.1.883 generate app MyMvc c:\Sencha\MyMvc

 

<그림 1> Sencha Cmd로 생성한 애플리케이션 폴더 구조

 

Sencha Cmd을 통해 생성된 애플리케이션의 주요 코드를 살펴보자. <리스트 1>은 app.js와 application.js의 코드다. 이 두 개의 파일에는 애플리케이션의 주요 설정이 들어있다. ①은 만들려는 애플리케이션 이름이다. 보통 패키지 명의 최상위 이름을 사용한다. ②에서는 application.js의 클래스를 상속했다. ③은 Viewport 객체를 자동으로 생성할 것인지를 설정하는 부분이다. 이때 값이 true이면 view 폴더의 Viewport 클래스를 자동으로 호출할 수 있다. ⑥은 ③이 false일 경우 이 함수 내부에서 Viewport를 별도로 생성하면 사용할 수 있다.

 

<리스트 1> app.js와 application.js 내부 코드

// app.js

Ext.application({

    name: 'MvcApp', // ① 애플리케이션 명

    extend: 'MvcApp.Application', // ② application.js를 상속했다.

    autoCreateViewport: true    // ③ view.Viewport의 인스턴스 생성

});

// application.js

Ext.define('MvcApp.Application', {

    name: 'MvcApp',        

    extend: 'Ext.app.Application',    // ④ 애플리케이션 실행 이후 처리

    controllers: [

        'FrameController'        // ⑤ 사용할 컨트롤러

    ],

    launch:function(){        // ⑥ 애플리케이션 실행 이후 처리

    }

});


<리스트 1>에서 autoCreateViewport를 true로 설정해 view 폴더에 Viewport.js 파일을 만들어 구현해야 한다. <리스트 2>와 같이 border layout을 사용해 서쪽, 북쪽, 중간에 container를 배치한다.

 

<리스트 2> Viewport.js 파일 코드

Ext.define('MvcApp.view.Viewport', {

    extend: 'Ext.container.Viewport',

    layout : 'border',

    items: [{

        region: 'north',

        xtype: 'container',

        height : 100,

        style : { borderColor : '#000000', borderStyle :'solid', borderWidth : '1px' }

    }, {

        region: 'center',

        xtype: 'container',

        style : { borderColor : '#000000', borderStyle :'solid', borderWidth : '1px' }

    }, {

        region: 'west',

        xtype : 'container',

        style : { borderColor : '#000000', borderStyle :'solid', borderWidth : '1px' },

        width: 200

    }]

});


이제 애플리케이션을 실행해 보자. <리스트 3>과 같이 Sencha Cmd에서 제공되는 웹서버를 작동시킨다.

 

<리스트 3> 애플리케이션 실행 코드

C:\Sencha>sencha fs web -port 8000 start -map c:\Sencha\MvcApp

Sencha Cmd v4.0.0.126

[INF] Starting shutdown listener socket

[INF] Listening for stop requests on: 1916

[INF] Mapping http://localhost:8080/ to c:\Sencha\MvcApp...

[INF] Starting http://localhost:8080

[INF] jetty-8.1.7.v20120910

[INF] NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet

[INF] started o.e.j.w.WebAppContext{/,file:/C:/Sencha/MvcApp/}

[INF] started o.e.j.w.WebAppContext{/,file:/C:/Sencha/MvcApp/}

[INF] Started SelectChannelConnector@0.0.0.0:8080

[INF] Started http://localhost:8080


브라우저에서 실행하면 <그림 2>와 같은 결과를 볼 수 있다.

<그림 2> index.html 실행 결과

 

그 다음 컨트롤러를 구현하자. controller 폴더에 FrameController.js 파일을 만들고 <리스트 4>와 같이 작성한다.

 

<리스트 4> FrameController.js 코드

Ext.define(' MvcApp.controller.FrameController', {

    extend : 'Ext.app.Controller',

    views : [],            // ① 참조할 뷰

    stores : [],        // ② 참조할 스토어

    refs : [],            // ③ 참조할 뷰 getter 설정

 

    init : function(app) {    // ④ 초기화

        this.control({        // ⑤ 현재 컨트롤러 영역

            'button' : {    // ⑥ 이벤트를 일으킨 컴포넌트

                click : function(){    // ⑦ 이벤트

                    console.log(arguments);

                }

            }

        });

    }

});


<리스트 4>를 자세히 살펴보자. ①에서는 컨트롤러가 참조할 View 클래스를 명시한다. 여기에 명시되면 각 뷰에서 발생하는 이벤트를 감지할 수 있다. ②에서는 애플리케이션에서 공유할 스토어를 명시했다. 단, 공유하지 않고 독립적으로 사용하는 스토어는 기입하지 않으며 각각의 View 클래스별로 따로 생성해야 문제가 없다.

③에는 참조된 View 클래스를 어떤 이름으로 사용할지 기입한다. 이 부분은 뒤에서 설명하겠다. ④는 컨트롤러의 핵심으로, 참조하는 모든 View 클래스에서 발생하는 이벤트를 감지하는 영역이다. ⑥과 ⑦은 Viewport의 Button에서 Click 이벤트가 발생하면 console.log를 실행하는 코드다.

이제 <리스트 4>가 작동되도록 <리스트 1>코드에 있는 ③ 'FrameController' 주석을 제거하고 <리스트 2>에서의 north 영역 코드를 <리스트 5>와 같이 수정하자.

 

<리스트 5> Viewport.js의 north 영역 코드

Ext.define(' MvcApp.view.Viewport', {

..

items: [{

region: 'north',

     xtype: 'button',

     text : 'Button',

     height : 100,

     style : { borderColor : '#000000', borderStyle :'solid', borderWidth : '1px' }

    },

    ..


코드를 실행하고 north 영역의 버튼을 선택하면 <그림 3>과 같은 결과를 얻을 수 있다. <그림 3>과 같이 선택된 버튼 이벤트를 컨트롤러가 감지해야 원하는 명령을 내릴 수 있다.

 

<그림 3> 버튼 추가 후 실행화면

 

이제 좀더 복잡한 코드를 만들어 보자. <그림 4>에서 빈 칸으로 남겨둔 views, stores, ref를 구현하겠다. 아직 비어있는 Viewport의 중간 패널에 간단한 그리드 패널을 추가하고 Click 이벤트를 가지고 특정 함수를 호출한다. <리스트 6>, <리스트 7>, <리스트 8>, <리스트 9>와 같이 클래스를 생성하고 각 폴더에 추가하자.

<리스트 6> Program Model 클래스

// app/model/Program.js

Ext.define(' MvcApp.model.Program', {

    extend: 'Ext.data.Model',

fields: [

        'pgm_nm',

        'pgm_class'

]

});


<리스트 7> Program Store 클래스

// app/store/Programs.js

Ext.define(' MvcApp.store.Programs', {

    extend : 'Ext.data.Store',

    autoLoad : false,

    model : ' MvcApp.model.Program',

    proxy : {

        type : 'ajax',

        url : '/json/programlist.json',

        reader : {

            type : 'json',

            root : 'entitys',

            totalProperty : 'totalCount',

            messageProperty : 'message'

        }

    }

});


<리스트 8> 스토어에 제공할 데이터 파일

// 웹루트에 json 폴더를 만들고 programlist.json 파일을 생성한다.

{"entitys":[{    "pgm_class":"benney.board.Board","pgm_nm":"게시판"},

            {    "pgm_class":"benney.login.Login","pgm_nm":"로그인"}],

"errMsg":"","errTitle":"검색결과","message":"","success":true,"totalCount":"2"

}


<리스트 9> 새로 추가할 그리드 클래스

Ext.define(' MvcApp.view.MyGrid',{

    extend : 'Ext.grid.Panel',

    alias : 'widget.mygrid',

    

    initComponent : function(){

        var me = this;

        Ext.apply(this, {

            store : 'Programs',

            columns : [{

                text : '클래스 이름 ',

                flex : 1,

                dataIndex : 'pgm_class'

            },{

                text : '프로그램명 ',

                flex : 1,

                dataIndex : 'pgm_nm'

            }]

        });

        me.callParent(arguments);

    }

});


이때 컨트롤러에서 <리스트 9>의 MyGrid 클래스와 Programs Store 클래스를 참조할 수 있게 코드를 수정한다.

 

<리스트 10> 변경된 컨트롤러 클래스

Ext.define(' MvcApp.controller.FrameController', {

    ..중략..

    views : ['MyGrid'],            // ① 참조할 뷰

    stores : ['Programs'],        // ② 참조할 스토어

    refs : [{

        ref : 'myGrid',

        selector : 'mygrid'

    }],            // ③ 참조할 뷰의 getter 설정

..

});

그리고 Viewport 클래스의 center 영역에 MyGrid 클래스의 widget명을 추가한다(<리스트 11> 참조).

<리스트 11> Viewport 클래스 center 영역 수정

{

    region: 'center',

    xtype: 'mygrid',

    style : { borderColor : '#000000', borderStyle :'solid', borderWidth : '1px' }

},


이제 브라우저를 재실행해 결과를 확인한다(<그림 4> 참조).

<그림 4> MyGrid 클래스를 추가한 결과

 

컨트롤러에 있는 views:[] 부분에 MyGrid 클래스를 등록해 Viewport 클래스에 있는 widget명인 'mygrid'로 사용할 수 있다. 만약 컨트롤러에 등록된 코드를 지우면 프로그램은 정상으로 작동하지 않는다.

그 다음 Viewport 상단 버튼을 선택해 하단 그리드에 있는 데이터가 표시되게 하고, 표시된 그리드를 선택하면 그리드 패널의 타이틀이 세팅되도록 <리스트 12>와 같이 수정하자.

 

<리스트 12> 수정된 FrameController 컨트롤러

Ext.define(' MvcApp.controller.FrameController', {

    ..        

    init : function(app) {    // ④ 초기화

        this.control({        // ⑤ 현재 컨트롤러 영역

            'button' : {    // ⑥ 이벤트를 일으킨 컴포넌트

                click : function(){    // ⑦ 이벤트

                    this.getStore('Programs').load();// ⑧

                }

            },

            'mygrid' : {    // ⑨

                itemclick : this.myGridClick    // ⑩

            }

        });

    },

    myGridClick : function(){

        var grid = this.getMyGrid();    // ⑪

        grid.setTitle('그리드 클릭');

    }

});

<리스트 12>를 자세히 설명하겠다. ⑥에 있는 이벤트를 발생시킨 컴포넌트로 인해 버튼에서 ⑦에서는 Click 이벤트가 발생했고, 그 결과 ⑧을 실행시킨다. ⑧에 있는 this.getStore() 메소드는 컨트롤러 상단 stores:[]에 등록된 스토어를 호출하게 해주고, 스토어의 load() 메소드가 호출됨으로써 그리드에 데이터가 출력된다.

⑨와 ⑩에서 그리드에 표시된 데이터 로우를 클릭하면 myGridClick 함수가 호출된다. 그리고 ⑪의 this.getMyGrid() 함수는 컨트롤러 상단의 ref 참조란에 표기된 ref:'myGrid'의 getter 메소드다. 또 this.getMyGrid() 함수를 통해 MyGrid 클래스의 인스턴스에 접근해 setTitle 메소드로 그리드 패널의 title 속성을 변경한 것이다.

변경된 코드를 실행하면 <그림 5>와 같은 결과를 얻을 수 있다.


<그림 5> 수정된 컨트롤러의 실행결과

 

이렇게 해서 하나의 MVC 애플리케이션을 완성했다. 이제 Sencha Cmd를 통해 배포과정을 진행해 보자. 애플리케이션 폴더로 이동해 <리스트 13>과 같이 빌드 과정을 진행한다.

 

<리스트 13> 애플리케이션 배포 코드

C:\Sencha\MvcApp>sencha app build

Sencha Cmd v4.0.0.126

[INF]

[INF] init-plugin:

[INF]

[INF] cmd-root-plugin.init-properties:

[INF]

[INF] init-properties:

… 중략…

[INF] -after-build:

[INF]

[INF] build:

[INF]

[INF] app-build:


빌드가 완료됐으니 최종 배포할 애플리케이션과 개발 단계의 애플리케이션이 어떻게 다른지 알아보자. <그림 6>은 빌드 전 캐시를 모두 지운 상태에서 최초로 실행한 결과이고, <그림 7>은 캐시를 이용 두 번째 실행한 결과를 개발자 도구에 있는 Network 탭에서 확인한 결과다.

 

<그림 6> 개발 버전의 최초 실행결과

 

<그림 7> 개발 버전의 두 번째 실행결과

 

이제 빌드를 완료한 배포판 애플리케이션을 실행하고 <그림 6>과 <그림 7>과 동일하게 <그림 8>과 <그림 9>처럼 확인하자. Sencha Cmd는 웹루트/build/MvcApp 이하에 애플리케이션을 빌드하므로 이를 브라우저에서 실행하면 된다.

 

<그림 8> 배포판의 최초 실행결과        

 

<그림 9> 배포판의 두 번째 실행결과

 

<그림 6>부터 <그림 9>까지의 결과를 정리한 것이 <표 1>이다.

 

 개발 버전

 배포 버전

 캐시 Ⅹ

 캐시 ○

 캐시 Ⅹ

 캐시 ○

 요청 파일 수

 13개

 13개

 4개

 3개

 전송용량

 6.8MB

 4.5KB

 2.2MB

 542Byte

 실행시간

 894ms

 503ms

 626ms

 68ms

<표 1> 개발 버전과 배포 버전의 네트워크 사용량 비교

 

<표 1>에서 캐시를 사용한 결과를 비교하자. Sencha Cmd는 빌드 시 사용되는 모든 클래스를 하나의 파일 합치고 공백과 변수 등을 1Byte로 줄여 전반적인 배포 용량을 줄였다. 이를 통해 실행시간 또한 대폭 줄어 든 것을 확인 수 있다. 이는 애플리케이션 규모가 커질수록 이런 빌드 과정이 절대적으로 필요함을 느끼게 해주는 부분이다.

 

정리하며

지금까지 ExtJS의 MVC 애플리케이션을 구현하고 Sencha Cmd를 통해 애플리케이션을 배포하는 과정을 알아봤다. 이후 진행될 연재에서는 지금까지 살펴본 것들을 가지고 게시판을 개발하면서 좀더 구체적인 ExtJS의 코드를 알아보겠다.

Posted by 베니94
자바스크립트/Ext JS2013. 9. 17. 20:13

ExtJS MVC구조를 통해 어플리케이션을 개발시 고민 중 하나가 컨트롤러의 등록이다. 

보통에 경우 app.js 즉 Ext.Application을 상속받은 클래스에 사용할 Controller를 등록하게 된다.


그러나 개발 시에는 매번 생성되는 컨트롤러를 app.js에 등록 하기 어렵고? 아니 귀찮고 규모가 큰 시스템에 경우

컨트롤러도 많아 지게 되어 모두 등록한다는 것 자체가 왠지 성능상에 좋지 않을 듯 싶다.


해서 생각한 것이 다이나믹하게 컨트롤러를 그때 그때 등록할수 있는 방법을 사용하게 된다.

대충 기술하자면 한개 정도의 미리 등록된 컨트롤러가 참조하고 있는 뷰를 통해 해당 컨트롤러에 

접근하면서 사용할 컨트롤러의 이름을 전달하고 접근과 동시에 application클래스에 특정 메소드를 호출하여

아래와 같이 새로운 컨트롤러를 등록하도록 하였다.

application안에서 컨트롤러를 등록하는 방법은 

var controller = this.getController('사용할 컨트롤러 클래스명');

controller.init(this); -> 여기서 this는 어플리케이션 클래스 이다.


문제는 이때 발생한다. 개발 모드에서 다이나믹하게 컨트롤러를 등록하여 사용할 수 있는 코드는 구축이 되었지만

실서버에 배포할 요량으로 빌드를 해보니 app.js에 등록되지 않은 컨트롤러는 빌드에서 빠지는 현상이 발생한다.


이는 ExtJS가 클래스의 종속성에 대해 검증하는 과정에서 사용되지 않는 즉 require가 없거나 참조관계 등이 없을 경우

실제 클래스 파일이 존재하는데도 빌드에서는 제외 시킨다는 것이다.


이 경우에는 Sencha Cmd로 생성한 어플리케이션 내의 build.xml파일을 수정하여 언제 사용될지 모르나 이미 존재하는 클래스를

빌드에 포함시키도록 할 수 있다.



어플리케이션 클래스
Ext.application({
    name: 'MyApp',
    appFolder: 'app',

    controllers: [
        "main.App"
    ],

    uses: [
        /*ant-generated-content-start*/ /*ant-generated-content-end*/
    ],

    autoCreateViewport: true,
});
build.xml

    

    

        
        
            
        
        
            
                
                
                    
                    
                        
                        
                    
                
            
        
        

        
        
    

    
        
        
    


참고 : http://stackoverflow.com/questions/14457508/using-sencha-cmd-with-dynamically-loaded-controllers
Posted by 베니94
자바스크립트/Ext JS2013. 6. 24. 23:40

안녕하세요 ExtJS 3번째 오프라인 강좌로 "ExtJS Class System & MVC 알아보기"를 
준비 했습니다.

ExtJS만의 클래스 시스템과 MVC 패턴을 통한 구현 방법을 알아보고 실무에 사용되는 
유용한 팁도 공유합니다. 

[강사소개]

    • 삼성SDS ExtJS 강의 수행
    • 한국센챠유저그룹 활동
    • 온오프믹스 ExtJS 강의 진행
    • ExtJS를 적용하여 다수의 시스템 구축 경험
    • Blog : http://benney.tistory.com

[세부 내역]

  • 대상 : ExtJS 초, 중급, ExtJs에 관심 있는 모든분들.
  • 일시 : 6월 29일(토) 17:00 ~ 19:00
  • 장소 : 토즈 강남 2호점(타워점 아닙니다.)
    • URL : http://www.toz.co.kr/branch/main/index.htm?id=11
  • 등록비용 : 50,000원
  • 등록하기 (http://onoffmix.com/event/16084)
  • 강의방식 : 준비 된 샘플을 통한 진행(실습아님)
  • 강의내용
    • ExtJS Class System
      1. Define & Create
      2. Config
      3. Extend & Mixins
      4. Static
      5. Dynamic Class Loading
    • ExtJS MVC의 소개
      1. MVC란 무엇인가?
      2. MVC를 통해 무엇을 얻을 수 있나?
      3. 각 요소에 대한 샘플을 보고 역할을 알 수 있다.
      4. Controller는 만능인가? 알고 쓰자 Controller


    • 기타 문의는 benneykwag@gmail.com으로 해주세요

      종료 후 뒷풀이를 하려고 합니다. 참석하신다는 분들이 있으면요 ^^
      (비용은 부담되지 않는 선에서 나누어 내도록 하시지요)


Posted by 베니94
자바스크립트/Ext JS2013. 4. 19. 10:29

안녕하세요 ExtJS 2번째 오프라인 강좌로 "ExtJS MVC 따라잡기"를 준비 했습니다.

ExtJS의 장점인 MVC 패턴을 통한 구현 방법을 알아보고 

TA, 개발PL 입장에서의 모듈화가 가능한 개발 구조가 어떤 것인지 알아봅니다.

[강사소개]

    • ExtJS적용 다수 시스템 구축 경험
    • 한국센챠유저그룹 활동
    • 삼성SDS ExtJS 강의 수행
    • 온오프믹스 ExtJS 강의 진행
    • Blog : http://benney.tistory.com

[ExtJS MVC 따라잡기]

  • 대상 : ExtJS에 관심있는 분, 막연히 MVC모델을 따라하는 분, TA입장에서 프로젝트 모듈화 및 구조를 고민하고 계신 분
  • 일시 : 5월 4일(토) 18:00 ~ 20:00
  • 장소 : 강남토즈타워점 (강남점, 강남2호점 아닙니다.!!)
    • URL : http://www.toz.co.kr/branch/main/index.htm?id=24
    • 주소 : 서울시 강남구 강남대로 84길 24-4
    • Map : http://durl.me/3p4m43
  • 등록비용 : 50,000원 (아래신청주소를 클릭하시고 온오프믹스에서 등록해주세요)
  • 신청주소 : http://onoffmix.com/event/14549
  • 강의방식 : 완벽히 실행가능한 소스를 통해 MVC구조를 설명 (실습X)
  • 강의내용
    • ExtJS MVC의 소개
      • MVC란 무엇인가?
      • MVC를 통해 무엇을 얻을 수 있나?
      • 각 요소에 대한 샘플을 보고 역할을 알 수 있다.
      • Controller는 만능인가? 알고 쓰자 Controller
    •  TA, PL입장에서 ExtJS MVC 구조
      • 대단위 프로젝트에서 어떤 형태로 모듈화를 해야하는가?
      • 개별 개발자간의 혼선을 줄이면서 개발할 수 있는 구성은 어떤 것인가?
      • 최종 배포는 어떤 모습이여야 하는가? Case별 장단점
      • 모듈별 개발은 어떤 모습으로 합쳐져 배포되어야 하는가?

기타 문의는 benneykwag@gmail.com으로 해주세요



Posted by 베니94
자바스크립트/Ext JS2013. 2. 24. 10:15

ExtJS강의교안(배포판).pdf

어제 ExtJS오프라인 강의를 잘 마쳤습니다.

오신분들 감사드리고 다음에 또 뵙겠습니다.


'자바스크립트 > Ext JS' 카테고리의 다른 글

Json 비교 사이트  (0) 2013.03.09
ExtJS4 IE8 textarea 버그?  (1) 2013.03.08
ExtJs 오프라인 강좌진행합니다.  (2) 2013.02.06
강좌 소스 올립니다.  (4) 2013.01.18
ExtJS 오픈라인 강의를 할까 생각중입니다.  (10) 2013.01.18
Posted by 베니94
자바스크립트/Ext JS2013. 2. 6. 23:10

ExtJS 오프라인 강좌 진행합니다.


일시 : 2/23 토요일 오후 7~9시

장소 : 토즈강남타워점


많은 참석 부탁드립니다.


아래에서 참석 신청해주세요

http://onoffmix.com/event/12445




Posted by 베니94