9.넥사크로플랫폼 스크립트 언어

Edit

넥사크로플랫폼 앱을 개발할 때는 자바스크립트 문법을 기본적으로 사용합니다. 자바스크립트 기본 문법에서 제공하지 않는 추가적인 기능을 처리하기 위해 별도 API를 제공합니다. 작성된 스크립트 코드는 빌드 과정을 거쳐 그대로 웹 브라우저나 모바일 디바이스에서 동작하도록 자바스크립트 코드로 변환됩니다.

이번 장에서는 넥사크로플랫폼에서 스크립트 작성 시 기본적으로 알아야 하는 문법적인 요소와 주의 사항을 설명합니다.

9.1유효범위(Scope)

유효범위는 접근 가능한 변수의 범위와 관련된 내용을 설명합니다. 유효범위 또는 영역이라고 표기하며 영문 표기 그대로 사용하기도 합니다. 업무에 사용하는 앱은 여러 개의 화면을 동시에 조작하거나 하나의 변수를 여러 화면에서 참조하는 경우가 많습니다. 유효범위를 사용하면 원하는 자원에 정확하게 접근할 수 있습니다.

9.1.1로컬 (local)

넥사크로플랫폼의 Form 스크립트에서 첫 번째 줄에 아래와 같은 코드가 있는 경우 로컬 변수로 처리됩니다. 일반적인 자바스크립트 코드였다면 전역 변수로 처리됩니다. 하지만 넥사크로플랫폼은 그렇지 않습니다.

var value0 = 0;

해당 코드가 빌드 과정을 거쳐 브라우저에서 동작하는 코드를 보면 어떤 차이가 있는지 확인할 수 있습니다. 빌드 과정을 거친 코드는 아래와 같습니다. 첫 번째 줄에 정의된 변수가 자동으로 생성된 함수 내에 포함되면서 로컬 변수로 처리됩니다.

this.registerScript("TEST.xfdl", function() {
    var value0 = 0;
});

Form 스크립트에서 전역 변수를 처리하고자 한다면 var 키워드를 사용하지 않고 변수를 정의할 수 있습니다. 하지만 전역 변수를 사용하면 앱 전체에 영향을 미칠 수 있어 적절한 유효범위를 지정해주어야 합니다.

함수 내에서 선언된 변수는 유효범위를 따로 지정하지 않고 사용할 수 있으며 매개변수로 전달된 값 역시 유효범위를 지정하지 않고 사용할 수 있습니다.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
     obj.set_text("button");
     var a = 3;
     trace(a); // 3
}

9.1.2this

Application 또는 Form에서 사용되는 항목에 대해 유효범위를 지정할 때는 항상 this를 사용합니다. 변수뿐 아니라 속성, Form 간의 참조 시에도 적절한 유효범위를 지정해주어야 합니다.

Form 내에서 변수는 아래와 같이 선언합니다.

this.formvalue = 4;

함수를 선언할 때도 유효범위를 지정해주어야 합니다. 또한, 함수를 작성할 때 Form 내에 선언된 변수를 참조할 때도 유효범위를 지정해주어야 합니다.

this.formvalue = 4;

this.test = function()
{
     this.formvalue = 3;
     this.parent.value = 3;
     this.parent.parent.value = 3;
}

trace나 alert와 같은 메소드는 지정된 유효범위에 따라 자바스크립트 기본 문법에서 제공하는 메소드를 사용하거나 넥사크로플랫폼에서 추가로 제공하는 메소드를 사용할 수 있습니다. 유효범위를 지정하지 않고 alert 메소드를 쓰는 것과 this 유효범위를 지정하는 것은 전혀 다른 메소드가 실행하는 것입니다.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
    alert(e.button); // JavaScript
    this.alert(e.button); // Form.alert()
    nexacro.getApplication.alert(e.button); // Application.alert()
}

함수 선언 시에도 유효범위를 지정해 해당하는 Application 또는 Form의 멤버로 포함되도록 합니다.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
...
}

eval 함수로 Form을 접근하는 경우에도 this를 사용해야 합니다.

eval("this.formfunc()");

아래와 같이 함수를 직접 선언할 수도 있지만, Global로 처리되며 이후 지원이 중단될 수 있으므로 권장하지 않습니다.


function Button00_onclick(obj:nexacro.Button, e:nexacro.ClickEventInfo)

{

...

}

9.1.3Global

넥사크로플랫폼 스크립트 내에서 유효범위를 지정하지 않은 변수나 함수는 모두 최상위 Global 멤버로 처리됩니다. 아래와 같이 유효범위를 지정하지 않고 사용된 스크립트는 모두 Global로 처리됩니다.

globalvar = 2; 
var globalvar2 = 3;

함수 내에 사용된 변수라도 유효범위를 지정하지 않으면 모두 Global로 처리됩니다. 단 var 키워드를 사용해 정의한 변수는 함수 밖에서 사용할 수 없습니다.

this.test = function()
{
    trace(globalvar); //2
    trace(globalvar2); //3
    
    value = 4;
    var localvar = 5;
}


this.test = function()
{
    trace(value); // 4
    trace(localvar); // ReferenceError: localvar is not defined
}

Form 내에서 다른 스크립트 파일을 include 하는 경우에는 내부적으로 스크립트를 함수로 처리합니다. 그래서 var 키워드를 사용할 때 주의해야 합니다.


예를 들어 includecode.xjs 파일 내 정의된 변수가 실제 generate 된 includecode.xjs.js 코드는 아래와 같습니다 (generate 된 코드는 버전에 따라 달라질 수 있습니다).

includecode.xjs

bbb = "bbb";
var ccc = "ccc";

includecode.xjs.js

(function()
{
    return function(path)
    {
        var obj;

        // User Script
        this.registerScript(path, function() {
            bbb = "bbb";
            var ccc = "ccc";
        });

        this.loadIncludeScript(path);
        obj = null;
    };
}
)();

함수를 선언하거나 호출할 때도 유효범위를 지정해주어야 합니다. 아래 스크립트에서 test()와 this.test()는 서로 다른 함수를 호출합니다. 유효범위를 지정하지 않고 test()를 호출하게 되면 Global에 선언된 test 함수를 호출합니다.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
     test();
     this.test();
}

아래와 같이 유효범위 없이 지정된 함수는 Global로 처리됩니다.

Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
...
}

function Button00_onclick(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
...
}

transaction()과 같은 Application 또는 Form 메소드는 해당하는 유효범위를 지정해주어야 합니다.


//application

nexacro.getApplication().exit("");

nexacro.getApplication().transaction("");


//Form

this.close("");

this.go("");

this.transaction("");

Application 전체에서 사용하고 싶은 변수는 Global 변수가 아닌 AppVariables로 등록해서 사용하는 것을 권장합니다.

nexacro.getApplication().addVariable("aaa", "TEST");
trace(nexacro.getApplication().aaa); // TEST

9.1.4Expr

Grid 컴포넌트 내에서 사용하는 expr 스크립트는 넥사크로플랫폼 내부적으로 바인딩 된 Dataset을 기준으로 처리되기 때문에 별도의 유효범위를 지정하지 않아도 사용할 수 있습니다. 바인딩 되지 않은 Dataset에 직접 접근하려면 유효범위를 지정해주어야 합니다.

아래와 같이 바인딩 된 Dataset에 대해 expr를 사용하는 경우에는 this를 붙이지 않습니다.

<Cell text="expr:Column00"/>
<Cell text="expr:Column00.min"/>
<Cell text="expr:currow"/>
<Cell text="expr:rowposition"/>
<Cell text="expr:getSumNF('col0')"/>
Dataset.set_filterstr("Column00=='test'");
Dataset.filter("Column00=='test'");

expr 스크립트 내에서 바인딩 된 Grid 오브젝트, Dataset 컴포넌트, Cell 오브젝트를 지정하고자 할 때는 아래와 같은 변수 또는 지시자를 사용합니다.

Grid: comp
Dataset: dataset
Cell: this
<Cell text="expr:this.col"/> <!-- Cell -->
<Cell text="expr:dataset.rowcount"/> <!-- Binded Dataset -->
<Cell text="expr:comp.currentcell"/> <!-- Grid -->
<Cell text="expr:dataset.parent.func1()"/> <!-- Form -->
<Cell text="expr:comp.parent.func1()"/> <!-- Form -->

Form에 대한 지시자를 별도로 제공하지 않으며 필요하면 comp.parent 또는 dataset.parent 와 같이 접근합니다.

Form 내에 있는 함수에 접근할 때 comp.parent.func() 형식을 사용하지 않고 this를 사용하게 되면 오류로 처리됩니다. expr 스크립트에서 this는 Cell 오브젝트를 가리킵니다.

<Cell text="expr:this.func01()"/>

컴포넌트 속성으로 Expr과 Text가 같이 있는 경우에 화면에 보이는 텍스트를 반환하는 getDisplayText 메소드를 사용할 수 있습니다.

this.Button00.set_text("text");
this.Button00.set_expr("1+1");

trace(this.Button00.text); // "text"
trace(this.Button00.expr); // "1+1"
trace(this.Button00.getDisplayText()); // "2"

9.1.5lookup

lookup 메소드는 유효범위를 지정해 접근하기 어려운 경우 사용할 수 있도록 설계된 추가 메소드입니다. 원하는 오브젝트나 함수를 id 또는 함수명을 가지고 찾을 수 있습니다.

lookup 메소드는 아래와 같은 형식으로 사용할 수 있습니다.

Form.lookup( strid );
nexacro.getApplication().lookup( strid );
[Component].addEventHandlerLookup( eventid, funcid, target );

실제 코드에서는 아래와 같이 사용됩니다.

// this에서 상위로 검색해서 objectid에 해당하는 오브젝트를 반환
var obj = this.lookup("objectid");

// this에서 상위로 검색해서 fn_onclick에 해당하는 함수를 반환
this.lookup("fn_onclick")();

// this에서 상위로 검색해서 fn_onclick에 해당하는 함수를 이벤트 핸들러에서 처리
btn00.addEventHandlerLookup( "onclick", "fn_onclick", this );

9.2이벤트 핸들러

이벤트 처리를 위한 이벤트 핸들러는 넥사크로 스튜디오 속성창에서 추가하거나 각 컴포넌트, 오브젝트에 제공하는 메소드를 사용해 스크립트에서 추가할 수 있습니다.

9.2.1메소드

스크립트 내에서 이벤트 처리를 위해 이벤트 함수를 추가, 설정하거나 삭제할 수 있는 메소드를 제공합니다.

addEventHandler( eventid, funcobj, target )
addEventHandlerLookup( eventid, funcstr, target )
setEventHandler( eventid, funcobj, target )
setEventHandlerLookup( eventid, functstr, target )
removeEventHandler( eventid, funcobj, target )
removeEventHandlerLookup( eventid, funcstr, target )

이벤트를 처리할 함수의 유효범위에 따라 적절한 메소드를 선택해 사용합니다.

this.btn00.setEventHandler("onclick", this.fn_onclick, this);
this.dataset00.addEventHandlerLookup("onrowposchange", "fn_onchange", this);

addEventHandlerLookup, setEventHandlerLookup, removeEventHandlerLookup 메소드는 앱 성능에 영향을 미칠 수 있으므로 필요한 경우만 사용을 권장합니다.

이벤트를 속성 창에서 생성하게 되면 아래와 같이 문자열로 설정됩니다.

<Button id="Button00" ... onclick="Button00_onclick"/>

해당 코드는 빌드 작업 후 변환된 자바스크립트 코드에서는 아래와 같이 this 지시자를 붙여서 생성됩니다.

this.Button00.addEventHandler("onclick", this.Button00_onclick, this);

9.2.2오브젝트 타입

넥사크로 스튜디오에서 이벤트 핸들러 함수에 매개변수를 설정할 때 오브젝트의 타입을 지정할 수 있습니다. 타입은 자바스크립트 표준 문법은 아니며 넥사크로 스튜디오 내부에서 개발 편의성을 제공하기 위해 지원되는 형식입니다.

this.Button00_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    trace(obj.text);
}

입력된 타입 값을 기준으로 넥사크로 스튜디오에서 인텔리센스 기능을 지원합니다.

해당 코드를 자바스크립트 코드로 변환할 때는 타입 값을 제거합니다.

this.Button00_onclick = function(obj,  e)
{
    trace(obj.text);
}

오브젝트 타입을 지정하지 않아도 앱이 실행하는데 영향을 미치지 않습니다.

이벤트 핸들러 함수 외 다른 함수에서는 오브젝트 타입을 지원하지 않으며 동작에 영향을 미칠 수 있습니다.

9.3Setter

ECMAScript 5부터는 Setter/Getter를 사용해 변수의 접근 제한을 처리할 수 있습니다. 하지만 IE8 이하 웹브라우저에서 지원할 수 없는 명세서이기 때문에 넥사크로플랫폼에서는 별도의 set 메소드를 제공합니다.

9.3.1set 메소드

예를 들어 Button 컴포넌트의 text 속성을 사용할 때는 아래와 같이 사용할 수 있습니다.

this.Button00.set_text("text");
trace(this.Button00.text);

아래와 같이 속성값에 직접 접근하는 방식은 더는 지원하지 않습니다.


this.Button00.text = "text";

사용자가 직접 추가한 오브젝트 속성에 접근할 때는 기존처럼 접근할 수 있습니다.


<Button myprop="333">

this.Button00.myprop = "333";

this.Button00.mytext = "text";

스타일 관련 속성에 접근하는 방식도 set 메소드를 사용합니다. 추가된 set 메소드에는 하위 속성까지 포함하고 있습니다. 기존 속성은 값을 가져올 때만 사용할 수 있습니다.

this.Button00.set_color('aqua');
trace(this.Button00.color); // 'aqua'

set 메소드를 호출하기 전에 스타일 속성값을 가져오려 하면 null 값이 나올 수 있습니다.

9.3.2동적인 속성

속성값을 가져오는 것은 기존과 같지만, 예외적으로 동적으로 속성값이 변경되는 오브젝트는 별도의 GetMethod를 제공합니다. System 오브젝트의 curx, cury, screenwidth, screenheight 4개 속성은 추가된 메소드를 사용해야 합니다.

nexacro.System.getCursorX();
nexacro.System.getCursorY();
nexacro.System.getScreenWidth();
nexacro.System.getScreenHeight();

컴포넌트 타입에 따라 사용하지 않는 속성은 접근할 수 없습니다. 예를 들어 Calendar 컴포넌트의 타입이 spin이 아닌 경우에는 아래 속성에 접근할 수 없습니다.

this.Calendar.spindownbutton
this.Calendar.spinupbutton

Calendar 컴포넌트에서 spindownbutton 속성은 컨트롤 속성(Control Property)이라고 하며 속성 자체를 문자열로 출력하면 [object ButtonControl]라고 표시됩니다.

9.4기타 변경 사항

9.4.1nexacro 메소드

ECMAScript에서 지원하지 않는 기능을 넥사크로플랫폼 자체적으로 수정해 사용하던 메소드는 지원하지 않습니다. 기존에 제공하던 기능은 nexacro 메소드로 별도 제공합니다.

예를 들어 Math 오브젝트에서 제공하던 메소드 중 2개의 인자를 지원하는 floor, ceil, round 메소드는 더는 제공되지 않습니다. 해당 메소드를 사용하려면 nexacro 메소드로 사용해야 합니다.

//Math.floor( v, digit );
nexacro.floor( v, digit );

//Math.ceil( v, digit );
nexacro.ceil( v, digit );

//Math.round( v, digit );
nexacro.round( v, digit );

또한, 자바스크립트에서 예약어로 사용하는 일부 오브젝트의 명칭이 변경되었습니다.

//new Image();
new nexacro.Image();

예약어와 중복되지 않는 나머지 컴포넌트도 TypeDefinition 내의 classname이 nexacro.Button과 같은 형식으로 변경되었습니다. 하지만 기존처럼 Button을 그대로 사용할 수 있습니다.

this.button00 = new Button();
or
this.button00 = new nexacro.Button();

속성이나 오브젝트도 예약어와 충돌되어 일부 변경되었습니다.


Component.class → Component.cssclass

ExcelExportObject.export() → ExcelExportObject.exportData()

VirtualFile.delete() → VirtualFile.remove()

9.4.2동작 방식 변경

자바스크립트에서 지원하지 않거나 다르게 동작하는 일부 항목이 수정되었습니다.

<> 비교 연산자 지원하지 않음

<> 비교 연산자를 더는 지원하지 않습니다. 다른 값을 비교할 때는 != 연산자를 사용하세요.

switch 문 내 문자열 처리 방식 변경

이전 버전에서는 switch 문 내에서 case "2" 와 case 2 가 같은 방식으로 처리되던 것을 별개의 값으로 처리합니다.

정규표현식 /g 옵션 적용 방식 변경

정규표현식에서 /g 옵션을 사용하지 않고 replace를 적용하게 되면 한 개의 항목만 변경되며 /g 옵션을 적용해야 전체 항목이 변경됩니다.

9.4.3오브젝트 명 생성 시 제약

컨테이너의 멤버인 속성, 메소드명과 같은 ChildName을 만들 수 없습니다. 예를 들어 Form은 text라는 속성이 있는데 추가된 버튼 컴포넌트의 id를 text로 지정할 수 없습니다. 아래 같은 경우 버튼이 생성되지 않습니다.

<Form text="formtext">
     <Layouts>
          <Layout>               
               <Button id="text'>

Dataset과 같은 Invisible 오브젝트 역시 Array의 멤버로 처리되어 length와 같은 속성을 id로 지정할 수 없습니다. 아래 같은 경우 컬럼이 생성되지 않습니다.

<Objects>
     <Dataset id="Dataset00">
          <ColumnInfo>
               <Column id="length" type="STRING" size="256"/>
          </ColumnInfo>

9.4.4변수명, 함수명 생성 시 제약

변수명이나 함수명 앞에 언더바(_)를 포함하는 경우 넥사크로플랫폼 라이브러리에서 사용하는 변수나 함수와 충돌할 수 있습니다. 이로 인해 화면이 보이지 않거나 의도와 다른 방향으로 앱이 동작할 수 있습니다.

예를 들어 아래의 경우 로딩이 완료되지 않고 화면이 보이지 않습니다. 넥사크로플랫폼 라이브러리에서 사용하는 _is_loading 변수와 같은 이름으로 변수명을 만들었습니다.

this._is_loading = true;
this.Button00_onclick = function(obj:Button,  e:nexacro.ClickEventInfo)
{
    trace(this._is_loading);
}

언더바(_)를 포함하지 않더라도 넥사크로플랫폼 라이브러리에서 사용하는 일부 변수명이나 함수명과 충돌할 수 있습니다.

예를 들어 아래의 경우 컴포넌트 생성이 완료되지 않고 화면이 보이지 않습니다. 넥사크로플랫폼 라이브러리에서 사용하는 createComponent 함수와 같은 이름으로 함수명을 만들었습니다.

this.createComponent = function()
{
    trace('createComponent ');
}

9.4.5추가 모듈에서 window 오브젝트 사용 시 제약

외부 라이브러리 또는 자바스크립트 파일을 모듈로 등록해 사용하는 경우 window 오브젝트가 포함된 코드는 프로젝트 로딩 시 넥사크로 스튜디오에서 에러가 발생할 수 있습니다.

넥사크로 스튜디오에서는 프로젝트를 로딩하면서 모듈로 등록된 코드를 분석하고 처리하는데 이 과정에서 NRE에서 지원하지 않는 window 오브젝트를 처리하면서 에러가 발생합니다. window 오브젝트를 처리하지 않도록 아래와 같이 코드 상단에 분기처리문를 추가하면 에러가 발생하지 않습니다.

if( system.navigatorname != "nexacro DesignMode") 
{    
    if (typeof JSON !== 'object') {
        JSON = {};
    }

    (function () {
...
        })  (window)        
    };