스크립트 분석과 작성 시 유의 사항( Form_ScriptSampe1.xfdl)

개발 시 유의사항

교육샘플 열기

1

프로젝트 오픈

다운 받은 폴더의 압축을 푼 다음 교육 교재인 EduSysN 프로젝트를 오픈합니다.
[menu] File > Open > Project : "EduSysN.xprj"를 선택하여 프로젝트를 오픈합니다.

2

Generate

다운 받은 교육 교재의 소스를 Generate 합니다. 
[menu] Generate > Application 를 선택하여 재너레이트 시킵니다.

화면의 구성

[샘플] Form::Form_ScriptSample1.xfdl

Form_ScriptSample1의 Form 구성

1 (Time 0_00_04;37)

화면구성

NO

구성

구성내용

1

검색조건

재직상태, 성명, 부서, 입사일자를 기준으로 사원정보 검색

( * 부서명은 Like 조건 )

2

사원목록

1에서 선택한 조건의 Dataset 'ds_emp'에 있는 사원 정보 List

3

기본정보

2에서 선택한 'ds_emp'에 있는 사원의 상세정보

4

상세정보

2에서 선택한 사원의 상세정보 (발령사항 - ds_appoint)

( * 학력사항과 경력사항은 없음)

개발시 가장 기본이 되는 마스터/디테일 형태로 구성되어 있습니다.

화면설계서

NO

설명

1

조회조건에 부서명은 Like 조건이므로 부서명의 일부만 입력해도 된다.

입사일자는 2014년도 까지 데이터가 존재하므로 from 입사일자 조건에 값을 지운다.

2

[조회] 버튼을 클릭하면 2에 사원목록을 표시합니다. 이때 부서명도 함께 표시됩니다.

화면의 ds_emp에는 DEPT_NAME 컬럼이 없으나 조회 시 서버에서 호출해오는 Dataset에는 DEPT_NAME 컬럼이 있습니다.

3

2의 row를 선택하면 해당 정보가 34에 출력합니다.

4

[입력] 버튼을 클릭하면 선택한 'ds_emp'에 있는 사원의 데이터를 추가합니다.

5

[삭제] 버튼을 클릭하면 선택한 'ds_emp'에 있는 사원의 데이터를 삭제합니다.

6

[저장] 버튼을 클릭하면 데이터 validation 을 체크하고 이상이 없는 경우 작업한 내용을 서버로 저장합니다.

Dataset의 구성

Dataset의 구성

NO

구성

구성내용

화면구성

1

ds_emp

선택 된 부서에 해당하는 사원정보

화면의 좌측 사원목록 데이터

2

ds_pos

직급 코드 정보

기본정보의 직급콤보의 데이터

3

ds_appoint

발령사항 Data

상세정보의 발령사항의 데이터

4

ds_status

재직상태

검색조건의 재직상태의 데이터

ds_pos 와 ds_status 는 코드성 데이터
<ColumnInfo>
  <Column id="CODE" type="STRING" size="32"/>
  <Column id="CODE_NAME" type="STRING" size="32"/>
</ColumnInfo>
<ColumnInfo>
  <Column id="EMPL_ID" type="STRING" size="10" description="사원번호"/>
  <Column id="FULL_NAME" type="STRING" size="50" description="성명"/>
  <Column id="DEPT_CD" type="STRING" size="10" description="부서코드"/>
  <Column id="POS_CD" type="STRING" size="10" description="직급코드"/>
  <Column id="HIRE_DATE" type="DATE" size="10" description="입사일자"/>
  <Column id="RETIRE_DATE" type="DATE" size="256" description="퇴사일자"/>
  <Column id="GENDER" type="STRING" size="10" description="성별"/>
  <Column id="PHONE_NO" type="STRING" size="10" description="연락처"/>
  <Column id="EMAIL" type="STRING" size="10" description="이메일"/>
  <Column id="STATUS" type="STRING" size="10" description="상태"/>
  <Column id="MEMO" type="STRING" size="256" description="특이사항"/>
  <Column id="CHK" type="STRING" size="256"/>
</ColumnInfo>
<Rows>
  <Row>
    <Col id="EMPL_ID">TS0123</Col>
    <Col id="FULL_NAME">Maria Kim</Col>
    <Col id="DEPT_CD">01</Col>
    <Col id="POS_CD">03</Col>
    <Col id="HIRE_DATE">20101003</Col>
    <Col id="GENDER">M</Col>
    <Col id="PHONE_NO">01723641258</Col>
    <Col id="EMAIL">mariakim@tobe.com</Col>
    <Col id="STATUS">A</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS0105</Col>
    <Col id="FULL_NAME">John Park</Col>
    <Col id="DEPT_CD">02</Col>
    <Col id="POS_CD">04</Col>
    <Col id="HIRE_DATE">20051011</Col>
    <Col id="GENDER">W</Col>
    <Col id="PHONE_NO">01774212521</Col>
    <Col id="EMAIL">johnpark@tobe.com</Col>
    <Col id="STATUS">A</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS0815</Col>
    <Col id="FULL_NAME">Henry Hong</Col>
    <Col id="DEPT_CD">03</Col>
    <Col id="POS_CD">03</Col>
    <Col id="HIRE_DATE">20070206</Col>
    <Col id="GENDER">M</Col>
    <Col id="PHONE_NO">01755669913</Col>
    <Col id="EMAIL">henryhong@tobe.com</Col>
    <Col id="STATUS">A</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS0717</Col>
    <Col id="FULL_NAME">Serry Park</Col>
    <Col id="DEPT_CD">04</Col>
    <Col id="POS_CD">02</Col>
    <Col id="HIRE_DATE">20090512</Col>
    <Col id="GENDER">W</Col>
    <Col id="PHONE_NO">01758998487</Col>
    <Col id="EMAIL">serrypark@tobe.com</Col>
    <Col id="STATUS">B</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS1001</Col>
    <Col id="FULL_NAME">Dennis An</Col>
    <Col id="DEPT_CD">01</Col>
    <Col id="POS_CD">04</Col>
    <Col id="HIRE_DATE">20010109</Col>
    <Col id="GENDER">M</Col>
    <Col id="PHONE_NO">01752563217</Col>
    <Col id="EMAIL">dennisan@tobe.com</Col>
    <Col id="STATUS">B</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS1225</Col>
    <Col id="FULL_NAME">Jackson Yu</Col>
    <Col id="DEPT_CD">02</Col>
    <Col id="POS_CD">03</Col>
    <Col id="HIRE_DATE">20160202</Col>
    <Col id="GENDER">W</Col>
    <Col id="PHONE_NO">01726532234</Col>
    <Col id="EMAIL">jacksonyu@tobe.com</Col>
    <Col id="STATUS">C</Col>
  </Row>
</Rows>
<ColumnInfo>
  <Column id="EMPL_ID" type="STRING" size="256"/>
  <Column id="APPOINT_DATE" type="DATE" size="256"/>
  <Column id="APPOINT_TYPE" type="STRING" size="256"/>
  <Column id="MEMO" type="STRING" size="256"/>
  <Column id="START_DATE" type="DATE" size="256"/>
</ColumnInfo>
<Rows>
  <Row>
    <Col id="EMPL_ID">TS0123</Col>
    <Col id="APPOINT_DATE">20101003</Col>
    <Col id="START_DATE">20101003</Col>
    <Col id="MEMO">입사</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS0105</Col>
    <Col id="APPOINT_DATE">20051011</Col>
    <Col id="START_DATE">20051011</Col>
    <Col id="MEMO">입사</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS0815</Col>
    <Col id="APPOINT_DATE">20070206</Col>
    <Col id="START_DATE">20070206</Col>
    <Col id="MEMO">입사</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS0717</Col>
    <Col id="APPOINT_DATE">20090512</Col>
    <Col id="START_DATE">20090512</Col>
    <Col id="MEMO">입사</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS1001</Col>
    <Col id="APPOINT_DATE">20010109</Col>
    <Col id="START_DATE">20010109</Col>
    <Col id="MEMO">입사</Col>
  </Row>
  <Row>
    <Col id="EMPL_ID">TS1225</Col>
    <Col id="APPOINT_DATE">20160202</Col>
    <Col id="START_DATE">20160202</Col>
    <Col id="MEMO">입사</Col>
  </Row>
</Rows>

component 명명규칙

컴포넌트에 id를 지정하는 이유는 스크립트에서 컴포넌트를 분별할 수 있도록 하기 위해서다.

1 (Time 0_00_04;37)

스크립트 분석하기

  1. 반복 또는 중복 되는 스크립트가 많다.

  2. 코드 데이터 가져올 때 2개의 transaction을 하나로 합칠 수 있다.

  3. 재직상태를 비동기로 처리해서 callback에 넣어둘 수 있다.

Form의 onload 이벤트

this.Form_onload

onload : Form 에 등록된 모든 컴포넌트와 데이터가 로드된 후 발생하는 이벤트입니다.

초기값 설정

  1. 검색조건 입사일자 From~To 셋팅하기 ( From 일자는 이번 달 1일 ~ To 일자는 오늘 날짜 )

  2. 코드 데이터 가져오기 ( 직급, 재직 상태 ) - jsp 실행해서 보여주기

  3. 검색조건의 재직상태 '전체' 표현하기

this.Form_onload = function(obj:nexacro.Form,e:nexacro.LoadEventInfo)
{

	// 초기값 설정 
	// 조회조건 입사일자 From:이번달 1일, To:오늘날짜
	var objDate = new Date();
	var sYear  = objDate.getFullYear().toString();
	var sMonth = (objDate.getMonth()+1).toString().padLeft(2, "0");
	var sDay   = objDate.getDate().toString().padLeft(2, "0"); 			
	this.div_search.form.cal_from.set_value(sYear+sMonth+"01");
	this.div_search.form.cal_to.set_value(sYear+sMonth+sDay);

	// 코드 데이터 가져오기 - 직급, 재직상태	
	// 직급
    var sSvcID    = "svcPositionCode";
    var sURL      = "SvcUrl::select_tbn_code_pos.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_pos=out_pos";
    var sParam    = "";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);
	
	// 재직상태
    var sSvcID    = "svcStatusCode";
    var sURL      = "SvcUrl::select_tbn_code_status.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_status=out_status";
    var sParam    = "";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack, false);

	//재직상태 '전체' 표현		   
	this.ds_status.insertRow(0);
	this.ds_status.setColumn(0, "CODE", "ALL");
	this.ds_status.setColumn(0, "CODE_NAME", "전체");
		
	// 재직상태 '전체' 선택
	this.div_search.form.rdo_status.set_value("ALL");
	
	//화면 로드시 데이터 조회
//	this.btn_search_onclick();	
};
재직상태의 '전체'를 표현하기 위해 select_tbn_code_status.jsp를 호출할 때 Transaction의 7번째 인자를 false지정했습니다

7번째는 동기/비동기 통신을 의미합니다.

false를 하게 되면 동기통신으로 하겠다는 것을 의미합니다.

동기(Sync)통신의 처리방식은 서비스를 호출하고 데이터를 다 받을 때까지 다음 스크립트가 동작하지 않고 대기하고 데이터를 다 받으면 다음 라인의 스크립트가 진행합니다.

성능향상을 위해 비동기(Async) 통신방식을 권장합니다.

조회

this.btn_search_onclick
조회 버튼을 클릭했을 때 사원정보와 상세정보를 가져옵니다.
검색조건에 조건을 줄 때 부서는 부서명 Like이고 입사일자는 시작일을 빼고 조회합니다.

입사일자가 오래전이라 조건을 줄 때 입사일자 시작일을 빼고 조회를 해야 데이터가 조회됩니다.

사원정보 가져오기

// 사원정보 가져오기 
var sSvcID    = "svcSelectEmp";
var sURL      = "SvcUrl::select_tbn_emp.jsp";
var sInDs     = "";
var sOutDs    = "ds_emp=out_emp";
var sParam    = "pStatus="    + this.div_search.form.rdo_status.value
	  + " pName="     + nexacro.wrapQuote(this.div_search.form.ed_name.value)
	  + " pDept="     + nexacro.wrapQuote(this.div_search.form.edt_dept.value)
	  + " pDateFrom=" + this.div_search.form.cal_from.value
	  + " pDateTo="   + this.div_search.form.cal_to.value;
var sCallBack = "fn_callback";
this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack, false);
가져온 사원정보를 가지고 상세정보를 조회 하기 위해 동기통신을 이용하였습니다.

상세정보 가져오기

// 상세정보 가져오기 
var sEmpID = this.ds_emp.getColumn(this.ds_emp.rowposition, "EMPL_ID");	
var sSvcID    = "svcSelectDetail";
var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
var sInDs     = "";
var sOutDs    = "ds_appoint=out_appoint";
var sParam    = "pEmpID='" + sEmpID + "'";
var sCallBack = "fn_callback";
this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);

콜백함수

this.fn_callback = function(svcID, errCD, errMSG)
{
	if(errCD < 0){
		this.alert("Error: " + svcID + " " + errMSG);
		return;
	}
}

입력

this.btn_add_onclick
  1. ds_emp에 row 추가하기

  2. 사원 데이터 입사일자에 오늘일자 설정

  3. ds_emp에 입사일 컬럼에 오늘일자 값 추가하기

var nRow = this.ds_emp.addRow();
this.div_detail.form.edt_name.setFocus();

//사원 데이터 입사일자에 오늘일자 설정
var objDate = new Date();
var sToday  = objDate.getFullYear().toString();
	sToday += (objDate.getMonth()+1).toString().padLeft(2, "0")
	sToday += objDate.getDate().toString().padLeft(2, "0"); 
this.ds_emp.setColumn(nRow, "HIRE_DATE", sToday);

삭제

this.btn_del_onclick
  1. 삭제여부를 묻기

  2. ds_emp에 해당 row 삭제하기

if(this.confirm("선택된 자료를 삭제 하시겠습니까?")){
	this.ds_emp.deleteRow(this.ds_emp.rowposition);
}

저장

this.btn_save_onclick

기존 데이터의 보존을 위해서 실제 저장은 안되고 있습니다.

validation

1

성명 필수입력 항목 체크

var sName = this.ds_emp.getColumn(i, "FULL_NAME");
if(sName == null || sName.length == 0){
	this.alert("성명은 필수입력 항목입니다.");
    this.ds_emp.set_rowposition(i);
	this.div_detail.form.edt_name.setFocus();
    return;
}

2

사원번호 필수입력 항목 체크

var sId = this.ds_emp.getColumn(i, "EMPL_ID");        
if(sId == null || sId.length == 0){		
	this.alert("사원번호는 필수입력 항목입니다.");
	this.ds_emp.set_rowposition(i);
	this.div_detail.form.msk_id.setFocus();
	return;
}

3

사원번호 5자리 체크

if(sId.trim().length != 5){
	this.alert("사원번호는 5자리 입니다.");
	this.ds_emp.set_rowposition(i);
	this.div_detail.form.msk_id.setFocus();
	return;
}

저장하기

var sSvcID    = "svcSaveEmp";
var sURL      = "SvcUrl::save_tbn_emp.jsp";
var sInDs     = "in_emp=ds_emp:u";
var sOutDs    = "";
var sParam    = "in_var1="+nexacro.wrapQuote(this.titletext) + " in_var2="+this.name ;
var sCallBack = "fn_callback_save";
this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);

콜백함수

this.fn_callback_save = function(svcID, errCD, errMSG)
{
	if(errCD < 0){
		this.alert("Error: " + svcID + " " + errMSG);
		return;
	}
    if(svcID == "svcSaveEmp"){		
		this.alert("저장되었습니다.");		
	}
}

부서 팝업

this.div_detail_btn_pop_dept_onclick
  1. Form::Popup_DeptSearch.xfdl 부서선택 팝업창을 띄운다.

  2. 콜백함수에서 선택된 부서코드와 부서명 가져와서 ds_emp 데이터 셋에 값 넣기

this.div_detail_btn_pop_dept_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
	var objChild = new ChildFrame("popDept", 0, 0, 300, 400);
	objChild.set_formurl("Form::Popup_DeptSearch.xfdl");
	objChild.set_openalign("center middle");
	objChild.set_dragmovetype("all");  

    objChild.showModal(this.getOwnerFrame()
                      , {}
                      , this
                      , "fn_callback_pop");	
};

this.fn_callback_pop = function(sPopupId, sReturn)
{
	if(sPopupId == "popDept")
	{
		if(sReturn.length > 0){
			var arrRtn = sReturn.split("|");
			this.ds_emp.setColumn(this.ds_emp.rowposition, "DEPT_CD"  , arrRtn[0]);
			this.ds_emp.setColumn(this.ds_emp.rowposition, "DEPT_NAME", arrRtn[1]);
		}
	}
}

사원목록 Grid

Cell 클릭 시 상세정보 가져오기

grd_emp_oncellclick
this.grd_emp_oncellclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo)
{

	// 상세정보 가져오기 
    var sEmpID = this.ds_emp.getColumn(this.ds_emp.rowposition, "EMPL_ID");	
    var sSvcID    = "svcSelectDetail";
    var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_appoint=out_appoint";
    var sParam    = "pEmpID='" + sEmpID + "'";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);	
};

사원관리 ds_emp의 rowposition 변경 시 상세정보 가져오기

this.ds_emp_onrowposchanged
this.ds_emp_onrowposchanged = function(obj:nexacro.NormalDataset,e:nexacro.DSRowPosChangeEventInfo)
{
	trace("ds_emp_onrowposchanged");
	// 상세정보 가져오기 
    var sEmpID = this.ds_emp.getColumn(e.newrow, "EMPL_ID");	
    var sSvcID    = "svcSelectDetail";
    var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_appoint=out_appoint";
    var sParam    = "pEmpID='" + sEmpID + "'";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);	
};
this.ds_emp_onrowposchanged 이벤트에서 또 상세정보를 가져오는 서비스를 호출했네요
이것은 언제 사용할까요 ? row의 포지션이 변경될 때 발생하는 이벤트입니다. 
방금 그리드 oncellclick의 경우에는 마우스를 이용해서 사용하는 경우 데이터를 잘 가져옵니다. 
하지만 마우스가 아닌 키보드를 이용하는 경우에는 데이터를 가져오지 못해요 이것을 해결하기 위해 
this.ds_emp_onrowposchanged 이벤트에서 서비스를 가져오도록 작성을 했습니다.

동일한 작업을 2개의 이벤트에서 작업하고 있는 것을 확인할 수 있습니다.

// 상세정보 가져오기 
var sEmpID = this.ds_emp.getColumn(this.ds_emp.rowposition, "EMPL_ID");	
var sSvcID    = "svcSelectDetail";
var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
var sInDs     = "";
var sOutDs    = "ds_appoint=out_appoint";
var sParam    = "pEmpID='" + sEmpID + "'";
var sCallBack = "fn_callback";
this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);

Head 클릭

this.tab_detail_Tabpage1_grd_appoint_onheadclick
  1. 전체 선택/ 해제 하기 (obj.setCellProperty("Head", e.cell, "text", sText); )

  2. 정렬하기 ( this.fn_girdSort(obj, e) )

var sType = obj.getCellProperty("head", e.cell, "displaytype");
var sText = "";
if(sType == "checkboxcontrol"){
	var objDs = obj.getBindDataset();
	if(objDs.getRowCount() < 1) return;
	
	sText = obj.getCellProperty("head", e.cell, "text");
	sText = (sText == "1" ? "0" : "1");	
	
	for(var i=0; i < objDs.rowcount; i++){
		objDs.setColumn(i, "CHK", sText);
	}
	obj.setCellProperty("Head", e.cell, "text", sText);	
}
this.CONST_NONE_MARK = "";
this.CONST_ASC_MARK = "↑";
this.CONST_DESC_MARK = "↓";
this.fn_gridSort = function (obj, e)
{
    if(obj.getCellProperty("head", e.cell, "displaytype") == "checkboxcontrol") return;
    var objDs     = obj.getBindDataset();
	var sColId    = obj.getCellProperty("body", e.cell, "text").split(":");
	var sHeadText = "";
	
	for(var i = 0; i<obj.getCellCount("head"); i++) 
	{
		sHeadText = obj.getCellText(-1, i) ;
		if(i == e.cell){
			if (sHeadText.substr(sHeadText.length-1) == this.CONST_ASC_MARK) {
				obj.setCellProperty("head", i, "text", sHeadText.substr(0, sHeadText.length - 1) + this.CONST_DESC_MARK);
				objDs.set_keystring("S:-" + sColId[1]);
			} 
			else if (sHeadText.substr(sHeadText.length-1) == this.CONST_DESC_MARK) {
				obj.setCellProperty("head", i, "text", sHeadText.substr(0, sHeadText.length - 1) + this.CONST_ASC_MARK);
				objDs.set_keystring("S:+" + sColId[1]);
			} 
			else {
				obj.setCellProperty("head", i, "text", sHeadText + this.CONST_ASC_MARK);
				objDs.set_keystring("S:+" + sColId[1]);
			}
		} 
		else {
			if(sHeadText != null & sHeadText != ""){
				if (sHeadText.substr(sHeadText.length - 1) == this.CONST_ASC_MARK || sHeadText.substr(sHeadText.length - 1) == this.CONST_DESC_MARK) 
				{
					obj.setCellProperty("head", i, "text", sHeadText.substr(0, sHeadText.length - 1));
				}
			}
		}
	}
}

상세정보 > 발령사항 > Grid

Head 클릭 시 정렬하기

this.tab_detail_Tabpage1_grd_appoint_onheadclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo)
{
	this.fn_gridSort(obj, e);	
};

소스 분석에 대한 개인의견 정리

지금까지 스크립트를 함께 살펴봤는데 어러분이 볼 때 어떤 느낌이 들까요
잘 짜인 스크립트일까요? 아니면 문제가 있는 스크립트일까요?

만약 잘못된 소스라고 생각한다면 어떤 것 때문에 그렇게 생각하시나요?

의견정리

  1. 중복되는 스크립트 정리하기

  2. 서비스 호출 방식이 동기식(Sync) 방식을 비동기식(Async)으로 수정하기

  3. 여러 번 서비스를 호출해서 각각 코드를 받아 온 부분을 한번의 서비스 호출로 여러 개의 코드 받아오기

  4. 콜백함수 수정하기 (비동기에 의한 처리 추가, 여러 개의 콜백 하나로 합치기)

전체소스
this.Form_onload = function(obj:nexacro.Form,e:nexacro.LoadEventInfo)
{

	// 초기값 설정 
	// 조회조건 입사일자 From:이번달 1일, To:오늘날짜
	var objDate = new Date();
	var sYear  = objDate.getFullYear().toString();
	var sMonth = (objDate.getMonth()+1).toString().padLeft(2, "0");
	var sDay   = objDate.getDate().toString().padLeft(2, "0"); 			
	this.div_search.form.cal_from.set_value(sYear+sMonth+"01");
	this.div_search.form.cal_to.set_value(sYear+sMonth+sDay);

	// 코드 데이터 가져오기 - 직급, 재직상태	
	// 직급
    var sSvcID    = "svcPositionCode";
    var sURL      = "SvcUrl::select_tbn_code_pos.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_pos=out_pos";
    var sParam    = "";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);
	
	// 재직상태
    var sSvcID    = "svcStatusCode";
    var sURL      = "SvcUrl::select_tbn_code_status.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_status=out_status";
    var sParam    = "";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack, false);

	//재직상태 '전체' 표현		   
	this.ds_status.insertRow(0);
	this.ds_status.setColumn(0, "CODE", "ALL");
	this.ds_status.setColumn(0, "CODE_NAME", "전체");
		
	// 재직상태 '전체' 선택
	this.div_search.form.rdo_status.set_value("ALL");
	
	//화면 로드시 데이터 조회
//	this.btn_search_onclick();	
};

// Retrieve Button
this.btn_search_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
	// 사원정보 가져오기 
    var sSvcID    = "svcSelectEmp";
    var sURL      = "SvcUrl::select_tbn_emp.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_emp=out_emp";
    var sParam    = "pStatus="    + this.div_search.form.rdo_status.value
	              + " pName="     + nexacro.wrapQuote(this.div_search.form.edt_name.value)
				  + " pDept="     + nexacro.wrapQuote(this.div_search.form.edt_dept.value)
				  + " pDateFrom=" + this.div_search.form.cal_from.value
				  + " pDateTo="   + this.div_search.form.cal_to.value;
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack, false);

	// 상세정보 가져오기 
    var sEmpID = this.ds_emp.getColumn(this.ds_emp.rowposition, "EMPL_ID");	
    var sSvcID    = "svcSelectDetail";
    var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_appoint=out_appoint";
    var sParam    = "pEmpID='" + sEmpID + "'";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);
			   
};

this.fn_callback = function(svcID, errCD, errMSG)
{
	if(errCD < 0){
		this.alert("Error: " + svcID + " " + errMSG);
		return;
	}
}

// Add Button
this.btn_add_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
	var nRow = this.ds_emp.addRow();
	this.div_detail.form.edt_name.setFocus();
	
	//사원 데이터 입사일자에 오늘일자 설정
	var objDate = new Date();
	var sToday  = objDate.getFullYear().toString();
	    sToday += (objDate.getMonth()+1).toString().padLeft(2, "0")
	    sToday += objDate.getDate().toString().padLeft(2, "0"); 
	this.ds_emp.setColumn(nRow, "HIRE_DATE", sToday);	
};

// Delete Button
this.btn_del_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    if(this.confirm("선택된 자료를 삭제 하시겠습니까?")){
        this.ds_emp.deleteRow(this.ds_emp.rowposition);
    }
};

// Save Button
this.btn_save_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
    for(var i=0; i<this.ds_emp.rowcount; i++)
    {
        if(this.ds_emp.getRowType(i) == 1)  continue;
        
        var sName = this.ds_emp.getColumn(i, "FULL_NAME");
		if(sName == null || sName.length == 0){
            this.alert("성명은 필수입력 항목입니다.");
            this.ds_emp.set_rowposition(i);
			this.div_detail.form.edt_name.setFocus();
            return;
        }
        var sId = this.ds_emp.getColumn(i, "EMPL_ID");        
		if(sId == null || sId.length == 0){		
            this.alert("사원번호는 필수입력 항목입니다.");
            this.ds_emp.set_rowposition(i);
			this.div_detail.form.msk_id.setFocus();
            return;
        }
        if(sId.trim().length != 5){
            this.alert("사원번호는 5자리 입니다.");
            this.ds_emp.set_rowposition(i);
			this.div_detail.form.msk_id.setFocus();
            return;
        }
    }

    var sSvcID    = "svcSaveEmp";
    var sURL      = "SvcUrl::save_tbn_emp.jsp";
    var sInDs     = "in_emp=ds_emp:u";
    var sOutDs    = "";
    var sParam    = "in_var1="+nexacro.wrapQuote(this.titletext) + " in_var2="+this.name ;
    var sCallBack = "fn_callback_save";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);

};

this.fn_callback_save = function(svcID, errCD, errMSG)
{
	if(errCD < 0){
		this.alert("Error: " + svcID + " " + errMSG);
		return;
	}
    if(svcID == "svcSaveEmp"){		
		this.alert("저장되었습니다.");		
	}
}

this.grd_emp_oncellclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo)
{
	trace("grd_emp_oncellclick");
	// 상세정보 가져오기 
    var sEmpID = this.ds_emp.getColumn(this.ds_emp.rowposition, "EMPL_ID");	
    var sSvcID    = "svcSelectDetail";
    var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_appoint=out_appoint";
    var sParam    = "pEmpID='" + sEmpID + "'";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);	
};

this.ds_emp_onrowposchanged = function(obj:nexacro.NormalDataset,e:nexacro.DSRowPosChangeEventInfo)
{
	trace("ds_emp_onrowposchanged");
	// 상세정보 가져오기 
    var sEmpID = this.ds_emp.getColumn(e.newrow, "EMPL_ID");	
    var sSvcID    = "svcSelectDetail";
    var sURL      = "SvcUrl::select_tbn_emp_appoint.jsp";
    var sInDs     = "";
    var sOutDs    = "ds_appoint=out_appoint";
    var sParam    = "pEmpID='" + sEmpID + "'";
    var sCallBack = "fn_callback";
	this.transaction(sSvcID, sURL, sInDs, sOutDs, sParam, sCallBack);	
};

 
this.div_detail_btn_pop_dept_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
	var objChild = new ChildFrame("popDept", 0, 0, 300, 400);
	objChild.set_formurl("Form::Popup_DeptSearch.xfdl");
	objChild.set_openalign("center middle");
	objChild.set_dragmovetype("all");  

    objChild.showModal(this.getOwnerFrame()
                      , {}
                      , this
                      , "fn_callback_pop");	
};

this.fn_callback_pop = function(sPopupId, sReturn)
{
	if(sPopupId == "popDept")
	{
		if(sReturn.length > 0){
			var arrRtn = sReturn.split("|");
			this.ds_emp.setColumn(this.ds_emp.rowposition, "DEPT_CD"  , arrRtn[0]);
			this.ds_emp.setColumn(this.ds_emp.rowposition, "DEPT_NAME", arrRtn[1]);
		}
	}
}

this.grd_emp_onheadclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo)
{
	var sType = obj.getCellProperty("head", e.cell, "displaytype");
    var sText = "";
	if(sType == "checkboxcontrol"){
        var objDs = obj.getBindDataset();
        if(objDs.getRowCount() < 1) return;
        
        sText = obj.getCellProperty("head", e.cell, "text");
        sText = (sText == "1" ? "0" : "1");	
        
		for(var i=0; i < objDs.rowcount; i++){
			objDs.setColumn(i, "CHK", sText);
		}
		obj.setCellProperty("Head", e.cell, "text", sText);	
    }
    else{
        this.fn_gridSort(obj, e);
    }
};

this.tab_detail_Tabpage1_grd_appoint_onheadclick = function(obj:nexacro.Grid,e:nexacro.GridClickEventInfo)
{
	this.fn_gridSort(obj, e);	
};


this.CONST_NONE_MARK = "";
this.CONST_ASC_MARK = "↑";
this.CONST_DESC_MARK = "↓";
this.fn_gridSort = function (obj, e)
{
    if(obj.getCellProperty("head", e.cell, "displaytype") == "checkboxcontrol") return;
    var objDs     = obj.getBindDataset();
	var sColId    = obj.getCellProperty("body", e.cell, "text").split(":");
	var sHeadText = "";
	
	for(var i = 0; i<obj.getCellCount("head"); i++) 
	{
		sHeadText = obj.getCellText(-1, i) ;
		if(i == e.cell){
			if (sHeadText.substr(sHeadText.length-1) == this.CONST_ASC_MARK) {
				obj.setCellProperty("head", i, "text", sHeadText.substr(0, sHeadText.length - 1) + this.CONST_DESC_MARK);
				objDs.set_keystring("S:-" + sColId[1]);
			} 
			else if (sHeadText.substr(sHeadText.length-1) == this.CONST_DESC_MARK) {
				obj.setCellProperty("head", i, "text", sHeadText.substr(0, sHeadText.length - 1) + this.CONST_ASC_MARK);
				objDs.set_keystring("S:+" + sColId[1]);
			} 
			else {
				obj.setCellProperty("head", i, "text", sHeadText + this.CONST_ASC_MARK);
				objDs.set_keystring("S:+" + sColId[1]);
			}
		} 
		else {
			if(sHeadText != null & sHeadText != ""){
				if (sHeadText.substr(sHeadText.length - 1) == this.CONST_ASC_MARK || sHeadText.substr(sHeadText.length - 1) == this.CONST_DESC_MARK) 
				{
					obj.setCellProperty("head", i, "text", sHeadText.substr(0, sHeadText.length - 1));
				}
			}
		}
	}
}