PageSourceSearch

https://ganghwa-resort.co.kr/framework/js/dataset/dataSet.js?version=1683880750000

js ganghwa-resort.co.kr collected 2026-10-07 22:06:09 UTC 151,953 bytes, 4,634 lines download raw bytes

1
2/**
3 * @class 데이터셑 클래스의 생성함수
4 * 이 함수는 columns와 list의 두 인자를 받을 수 있다.
5 * <pre>
6 * 만약 인자가 하나만 주어지는 경우는 columns는 columns와 list 두가지로 해석될 수 있는데
7 * 만약 columns가 문자열 배열도 아니고 DataSet.DataSetColumn의 배열도 아닌 json 객체의 배열인 경우 list인 것으로 간주한다.
8 * 그렇지 않고 columns와 list가 모두 주어진 경우는 list는 데이타이고 columns는 컬럼 정의인 것으로 간주된다.
9 * 이런 경우의 columns는 다음과 같은 4가지 방법 모두로 정의가 가능하다.
10 *        1) 컬럼명의 문자열 배열
11 *           ex) ["column1","column2","column3"]
12 *        2) DataSet.DataSetColumn 의 배열
13 *           ex) [ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]
14 *        3) json 객체 배열 (객체의 가능한 속성은 columnId , dataType , columnTitle , fmt , isVirtual , maxLength , dispFmt 이다 )
15 *           ex) [ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ]
16 *        4) json 객체 ( 필드명을 키로 하고 컬럼 정보를 속성으로 하는 json 객체이다. 컬럼 정보의 속성은 fieldType , fieldTitle , fieldFormat , virtualField , fieldLength , fieldDisplayFormat 이 가능하다. )
17 *           ex) { "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" } , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }
18 * 이런 정의방법에 의해 다음과 같은 정의가 가능하다
19 * ex)
20 * new DataSet(["column1","column2","column3"])
21 * new DataSet(["column1","column2"],[{column1:"A",column2:"1"},{column1:"B",column2:"2"}])
22 * new DataSet([ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]);
23 * new DataSet([ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ],[{column1:"A",column2:"20160102"},{column1:"B",column2:"20160203"}]);
24 * new DataSet([{column1:"A",column2:"1"},{column1:"B",column2:"2"}]):권장하지는 않습니다.
25 * new DataSet([ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ], [{column1:"A",column2:"1"},{column1:"B",column2:"2"}])
26 * new DataSet({ "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" } , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }, [{column1:"A",column2:"1"},{column1:"B",column2:"2"}])
27 * </pre>
28 * @constructor
29 * @param columns 컬럼 목록
30 * <pre>
31 *        columns의 종류는 총 4가지가 가능하다.
32 *        1) 컬럼명의 문자열 배열
33 *           ex) ["column1","column2","column3"]
34 *        2) DataSet.DataSetColumn 의 배열
35 *           ex) [ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]
36 *        3) json 객체 배열 (객체의 가능한 속성은 columnId , dataType , columnTitle , fmt , isVirtual , maxLength , dispFmt 이다 )
37 *           ex) [ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ]
38 *        4) json 객체 ( 필드명을 키로 하고 컬럼 정보를 속성으로 하는 json 객체이다. 컬럼 정보의 속성은 fieldType , fieldTitle , fieldFormat , virtualField , fieldLength , fieldDisplayFormat 이 가능하다. )
39 *           ex) { "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" }
39 , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }
40 * </pre>
41 * @param list <pre>데이타 목록 json 객체의 배열 만약 list가 생략되고 columns만 있는 경우에 한하여
42 *        columns가 String의 배열도 아니고 DataSet.DataSetColumn의 배열도 아닌 일반 객체의 배열인 경우
43 *        columns는 list인 것으로 간주된다.
44 *        </pre>
45 * @returns this{DataSet}
46 * @author Jun.
47 * @since 2013-03-28
48 * @version 1.0
49 */
50
51DataSet = function(columns, list) { // 데이터셑
52	if (!(this instanceof DataSet)) { // new 없이 호출되면 new를 붙여서 다시 호출한다.
53		return new DataSet(columns, list);
54	}
55	this.init(columns, list);
56};
57/**
58 * 데이타셑의 행 상태 정의
59 */
60DataSet.DataSetStatus = { // 데이터셑Row의 상태
61	"NORMAL" : "NORMAL",
62	"INSERT" : "INSERT",
63	"UPDATE" : "UPDATE",
64	"DELETE" : "DELETE"
65};
66
67/**
68 * 데이타 타입 정의
69 */
70DataSet.DataType = {
71	"STRING" : "STRING",
72	"NUMBER" : "NUMBER",
73	"DECIMAL" : "DECIMAL",
74	"DATE" : "DATE",
75	fromString : function(str) {
76		if (str in this) {
77			return this[str];
78		}
79		throw "올바르지 않은 데이타 타입입니다." + (str);
80	}
81};
82
83/**
84 * 상수 정의
85 */
86/**
87 * 내부적으로 사용하는 rowId 컬럼 정의
88 */
89DataSet.RowIdColumn = "__rowId__";
90/**
91 * 내부적으로 사용하는 행번호 컬럼 정의
92 */
93DataSet.RowNoColumn = "__rowNo__";
94/**
95 * 내부적으로 사용하는 행 상태 컬럼 정의
96 */
97DataSet.StatusColumn = "rowStatus";
98/**
99 * 내부적으로 사용하는 메타 데이타의 데이타셑 이름 컬럼
100 */
101DataSet.DataSetNameColumn = "__dataSetName__";
102/**
103 * 내부적으로 사용하는 변경전 행 데이타 컬럼
104 */
105DataSet.OrgRowColumn = "jsOrignRowData";
106
107/**
108 * 상수 정의
109 */
110/** 날짜의 저장 형식 지정
111 */
112DataSet.DEFAULT_DATE_FORMAT = Date.__SAVE_FORMAT__;
113/**
114 * 저장하지 않고 진행하겠는지 물어보는 메시지 지정
115 */
116DataSet.CHECK_SAVE_MESSAGE = "gw.cfm.noSaveContinue";
117/**
118 * 행 삽입시 마스터 행이 없다는 메시지
119 */
120DataSet.NO_PARENT_ROW_MESSAGE = "gw.info.masterrow";
121/**
122 * 먼저 저장 후 작업하시라는 메시지
123 */
124DataSet.SAVE_PARENT_FIRST_MESSAGE = "gw.warn.saveFirst";
125/**
126 * 메타 데이타 데이타셑 이름
127 */
128DataSet.META_DATASET_NAME = "__metaDataSet__";
129
130
131/**
132 * 이벤트 목록 정의
133 */
134DataSet.EventNames = [ "valueChanged", "rowPositionChanging","rowPositionChanged", "rowInserted", "rowDeleted", "rowSwapped","beforeInsert", "beforeDelete" ];
135
136/**
137 * 데이타셑 초기화 함수
138 * 내부적으로 사용되는 데이타셑 초기화 함수
139 * 이 함수는 columns와 list의 두 인자를 받을 수 있다.
140 * <pre>
141 * 만약 인자가 하나만 주어지는 경우는 columns는 columns와 list 두가지로 해석될 수 있는데
142 * 만약 columns가 문자열 배열도 아니고 DataSet.DataSetColumn의 배열도 아닌 json 객체의 배열인 경우 list인 것으로 간주한다.
143 * 그렇지 않고 columns와 list가 모두 주어진 경우는 list는 데이타이고 columns는 컬럼 정의인 것으로 간주된다.
144 * 이런 경우의 columns는 다음과 같은 4가지 방법 모두로 정의가 가능하다.
145 *        1) 컬럼명의 문자열 배열
146 *           ex) ["column1","column2","column3"]
147 *        2) DataSet.DataSetColumn 의 배열
148 *           ex) [ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]
149 *        3) json 객체 배열 (객체의 가능한 속성은 columnId , dataType , columnTitle , fmt , isVirtual , maxLength , dispFmt 이다 )
150 *           ex) [ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ]
151 *        4) json 객체 ( 필드명을 키로 하고 컬럼 정보를 속성으로 하는 json 객체이다. 컬럼 정보의 속성은 fieldType , fieldTitle , fieldFormat , virtualField , fieldLength , fieldDisplayFormat 이 가능하다. )
152 *           ex) { "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" }
152 , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }
153 * 이런 정의방법에 의해 다음과 같은 정의가 가능하다
154 * ex)
155 * new DataSet(["column1","column2","column3"])
156 * new DataSet(["column1","column2"],[{column1:"A",column2:"1"},{column1:"B",column2:"2"}])
157 * new DataSet([ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]);
158 * new DataSet([ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ],[{column1:"A",column2:"20160102"},{column1:"B",column2:"20160203"}]);
159 * new DataSet([{column1:"A",column2:"1"},{column1:"B",column2:"2"}]):권장하지는 않습니다.
160 * new DataSet([ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ], [{column1:"A",column2:"1"},{column1:"B",column2:"2"}])
161 * new DataSet({ "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" } , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }, [{column1:"A",column2:"1"},{column1:"B",column2:"2"}])
162 * </pre>
163 * @author 김흥수
164 * @since 2015-09-21
165 * @version 1.0
166 */
167DataSet.prototype.init = function(columns, list) {
168	this.log = alert; // 로그를 찍을 대상을 지정함
169	this._filter = null; // 필터할 함수를 담음.
170	// this._column 컬럼정보 사용여부 고려
171	this._rows = []; // 실제 데이터 Rows
172	this._lastId = -1;
173	this._deletedRows = []; // 삭제된 데이터 Rows
174	this._view = null; // 바이딩 혹은 필터에 의해 보여질 가상 데이터 Row
175	this._columns = new DataSet.DataSetColumns();
176	this._pos = -1;
177	this._binder = new DataSet.Bind(this);
178	this.option = {}; // 향후 이벤트 혹은 다양한 옵션을 지정할수 있게 처리
179	this._events = {};
180	this._validator = null;
181	this._validatorFilter = "U"; // 기본저으로 변경된 행만 검사대상으로 삼는다.( New Or Updated
182	this._formBind = false;
183									// )
184	this._children = [];
185	this._title = null;
186	this._validatorData = {};
187	//DataSet.EventNames.forEachL(function(eventName) {
188	Array.prototype.forEachL.call(DataSet.EventNames,function(eventName) {
189		this._events[eventName] = {
190			"handlers" : []
191		};
192	}, this);
193
194	this.suppressEvent = false;
195
196	if (typeof (columns) != "undefined") {
197		if (columns instanceof Array) {
198			if (typeof (columns[0]) == "string" || columns[0] instanceof DataSet.DataSetColumn) {
199				this._columns = new DataSet.DataSetColumns(columns);
200				if (!gf_IsObjNull(list)) {
201					this.setAllData(list);
202				}
203			} else if (typeof (columns[0]) == "object") {
204				if(gf_IsObjNull(list)) {
205					this._columns = DataSet.DataSetColumns.makeFromList(columns);
206					this.setAllData(columns);
207				} else {
208					this._columns = new DataSet.DataSetColumns(columns);
209					this.setAllData(list);
210				}
211			}
212		} else {
213			this._columns = new DataSet.DataSetColumns(columns);
214			if (!gf_IsObjNull(list)) {
215				this.setAllData(list);
216			}
217		}
218	}
219};
220
221/**
222 * 새로운 행 id를 생성한다.
223 * 내부적으로 사용한다.
224 * @returns Number 새로운 행 아이디
225 * @author 김흥수
226 * @since 2015-10-06
227 * @version 1.0
228 */
229DataSet.prototype.newId = function() {
230	this._lastId++;
231	return this._lastId;
232};
233
234/**
235 * 데이타셑의 타이틀을 알아낸다
236 *
237 * @returns String 데이타셑의 타이틀
238 * @author 김흥수
239 * @since 2015-10-06
240 * @version 1.0
241 */
242DataSet.prototype.getTitle = function() {
243	return this._title;
244};
245
246/**
247 * 데이타셑의 타이틀을 설정한다.
248 *
249 * @param title 설정할 타이틀
250 * @author 김흥수
251 * @since 2015-10-06
252 * @version 1.0
253 */
254DataSet.prototype.setTitle = function(title) {
255	this._title = title;
256};
257
258/**
259 * 데이타셑의 validator에서 사용할 정보를 가져온다.
260 *
261 * @param id(String) validator id
262 * @returns Object validator가 사용하는 부가 정보
263 * @author 김흥수
264 * @since 2015-10-15
265 * @version 1.0
266 */
267DataSet.prototype.getValidatorData = function(id) {
268	return this._validatorData[id];
269};
270
271/**
272 * 데이타셑의 validator에서 사용할 정보를 설정한다.
273 *
274 * @param id(String) validator id
275 * @param data(Object) validator가 사용하는 부가 정보
276 * @author 김흥수
277 * @since 2015-10-15
278 * @version 1.0
279 */
280DataSet.prototype.setValidatorData = function(id,data) {
281	this._validatorData[id] = data;
282};
283
284/**
285 * 자식 데이타셑을 등록한다.
286 *
287 * @param dataSet 자식 데이타셑
288 * @param title 자식 데이타셑의 타이틀
289 * @param relation 자식 데이타센과 부모 데이타셑과의 관계, [{"parent":"부모쪽키1","child":"참조하는자식키1"},{"parent":"부모쪽키2","child":"참조하는 자식키2"}...]
290 * @param callbackFuncs <pre>
291 *            callback 함수 목록 {"checkUpdated":변경여부함수,"retrieve":조회함수}
292 *            checkUpdated 의 스펙은 function() { return boolean; }
293 *            retrieve 의 스펙은 function(args,masterDataSetRow ) {} 이다.
294 *            checkUpdated는 생략 가능하며 생략되면 자동으로 dataSet.isUpdate가 사용된다.
295 *            retrieve의 첫 인자는 부모행의 데이타셑 행을 relation 정보에 따라 매핑한 json 객체이다.
296 *            </pre>
297 * @author 김흥수
298 * @since 2015-10-08
299 * @version 1.0
300 */
301DataSet.prototype.registerChild = function(dataSet, relation,callbackFuncs) {
302	if (gf_IsObjNull(dataSet)) {
303		alert("데이타셑을 등록하십시오.");
304		throw "데이타셑을 등록하십시오.";
305	}
306	callbackFuncs = gf_Default(callbackFuncs,{});
307	callbackFuncs.checkUpdated = gf_Default(callbackFuncs.checkUpdated,
308			function() {
309				dataSet.saveRow();
310				return dataSet.isUpdate();
311			});
312	relation = gf_Default(relation, []);
313	this._children.push({
314		"dataSet" : dataSet,
315		"relation" : relation,
316		"callbackFuncs" : callbackFuncs
317	});
318	var that = this;
319	if(relation.length > 0 ) {
320		dataSet.bindEvent("beforeInsert",function(args){
321			if(that.getPosition() < 0 ) {
322				if(gf_IsNull(that.getTitle())) {
323					alert("부모 데이타셑에 타이틀을 등록하여 주십시오.(dataSet.setTitle('데이타셑 명칭'))");
324					throw "부모 데이타셑에 타이틀을 등록하여 주십시오.(dataSet.setTitle('데이타셑 명칭'))";
325				}
326				gf_AlertMsg(DataSet.NO_PARENT_ROW_MESSAGE,[that.getTitle()]);
327				return false;
328			}
329			if(that.getStatus(that.getPosition()) == DataSet.DataSetStatus.INSERT) {
330				if(gf_IsNull(that.getTitle())) {
331					alert("부모 데이타셑에 타이틀을 등록하여 주십시오.(dataSet.setTitle('데이타셑 명칭'))");
332					throw "부모 데이타셑에 타이틀을 등록하여 주십시오.(dataSet.setTitle('데이타셑 명칭'))";
333				}
334				gf_AlertMsg(DataSet.SAVE_PARENT_FIRST_MESSAGE,[that.getTitle()]);
335				return false;
336			}
337		});
338		dataSet.bindEvent("rowInserted",function(args){
339			var parentRow = that.getRowRefInView(that.getPosition());
340			//relation.forEachL(function(relInfo){
341			Array.prototype.forEachL.call(relation,function(relInfo){
342				args.dataSetRow.set(relInfo.child,parentRow.get(relInfo.parent));
343			});
344		});
345	}
346};
347
348/**
349 * 자식 데이타셑이 변경되었는지 검증한다. return true이면 변경된 것이 없다는 뜻이거나 변경 상관없이 진행하겠다는 뜻
350 *
351 * @returns boolean 자식이 변경되지 않은 경우 또는 변경된 것을 사용자가 무시하고 진행하겠다고 한 경우 true
352 * @author 김흥수
353 * @since 2015-10-08
354 * @version 1.0
355 */
356DataSet.prototype.checkChildrenUpdated = function() {
357	if(this.isChildrenUpdated()) {
358		if(!gf_ConfirmMsg(DataSet.CHECK_SAVE_MESSAGE)){
359			return false;
360		}
361	}
362	return true;
363};
364
365/**
366 * 자식 데이타셑이 변경되었는지 검증한다.변경된 자식이 있으면 true
367 *
368 * @returns boolean 변경된 자식이 있는 경우 true
369 * @author 김흥수
370 * @since 2015-10-08
371 * @version 1.0
372 */
373DataSet.prototype.isChildrenUpdated = function() {
374	if (gf_IsObjNull(this._children))
375		return false;
376	var ret = true;
377	//this._children.forEachStoppable(function(child){
378	Array.prototype.forEachStoppable.call(this._children,function(child){
379		var changed = child.callbackFuncs.checkUpdated.call(null);
380		if(changed) {
381			ret = false;
382			return true;
383		}
384		changed = child.dataSet.isChildrenUpdated.call(child.dataSet);
385		if(changed) {
386			ret = false;
387			return true;
388		}
389		return false;
390	});
391	return ! ret;
392};
393
394/**
395 * 자식을 조회한다.
396 * @param newRowIndex : 이동할 행 인덱스
397 * @author 김흥수
398 * @since 2015-10-08
399 * @version 1.0
400 */
401DataSet.prototype.retrieveChildren = function(newRowIndex) {
402	newRowIndex = gf_Default(newRowIndex,this.getPosition());
403	var dataSetRow = newRowIndex < 0 ? null: this.getRowRefInView(newRowIndex);
404	//this._children.forEachL(function(child){
405	Array.prototype.forEachL.call(this._children,function(child){
406		if(gf_IsObjNull(dataSetRow) || dataSetRow.getStatus() == DataSet.DataSetStatus.INSERT ) {
407			child.dataSet.clear();
408		} else {
409			var arg = {};
410			//child.relation.forEachL(function(relInfo){
411			Array.prototype.forEachL.call(child.relation,function(relInfo){
412				arg[relInfo.child] = dataSetRow.get(relInfo.parent);
413			});
414			if(! gf_IsObjNull(child.callbackFuncs) && ! gf_IsObjNull(child.callbackFuncs.retrieve)) {
415				child.callbackFuncs.retrieve.call(null,arg,dataSetRow);
416			}
417		}
418	});
419};
420
421/**
422 * 데이타셑에 검증로직을 설정한다.
423 *
424 * @param validator <pre>
425 *            검증 함수 function(dataSetRow) {} , return null; 이면 정상, return {"column":"컬럼명" , "message" : "검증 메시지"} 이면 해당 문제가 있다는 것임.
426 *            실제 사용하는 방법은 checkValid 함수를 이용하여 다음과 같은 식으로 정의한다.
427 *            ex)
428 *  ds_SysCdList.setValidator(function(dataSetRow){
429 *       return dataSetRow.checkValid([
430 *                                    {validator:"required", infos:[
431 *                                                                      {column:"sysCd" }
432 *                                                                      ,{column:"sysNm" }
433 *                                                                      ]
434 *                                    }
435 *                                    ,{validator:"maxLength", infos:[
436 *                                                                        {column:"sysCd" , maxLength:4 }
437 *                                                                        ]
438 *                                    }
439 *                                    ,{validator:"unique", infos:[
440 *                                                                    {column:"sysCd" , keys : "sysCd" }
441 *                                                                    ]
442 *                                    }
443 *                                    ]);
444 * }, "U");
445 * </pre>
446 * @param validatorFilter 체크할 행의 조건 "U" : 행상태가 New , Updated 인 경우만 , "A" : 전체 행
447 * @author 김흥수
448 * @since 2015-10-07
449 * @version 1.0
450 */
451DataSet.prototype.setValidator = function(validator, validatorFilter) {
452	this._validator = validator;
453	this._validatorFilter = validatorFilter;
454};
455
456/**
457 * 데이타셑에 현재 데이타셑이 valid한지 검증
458 *
459 * @param gotoInvalid :
460 *            문제가 발생한 곳으로 포커스를 이동할 것인지 결정한다. 기본값은 true
461 * @author 김흥수
462 * @since 2015-10-07
463 * @version 1.0
464 */
465DataSet.prototype.isValid = function(gotoInvalid) {
466	this._validatorData = {};
467	gotoInvalid = gf_Default(gotoInvalid, true);
468	if (gf_IsObjNull(this._validator)) {
469		return true;
470	}
471	var ret = true;
472	var that = this;
473	this.forEachStoppableInRows(function(dataSetRow, rowIdx) {
474		if (!dataSetRow.isChanged() && that._validatorFilter == "U")
475			return false;
476		var retInfo = that._validator.call(null, dataSetRow);
477		if (gf_IsObjNull(retInfo))
478			return false;
479		alert(retInfo.message);
480		if (gotoInvalid) {
481			var index = that.getRowIndexInView(dataSetRow);
482			if (index >= 0) {
483				if ( index != that.getPosition())
484					that.setPosition(index, true);
485				if (!gf_IsObjNull(retInfo.column)) {
486					setTimeout(function() {
487						that.focusTo(retInfo.column);
488					}, 0);
489				}
490			}
491		}
492		ret = false;
493		return true;
494	});
495	return ret;
496};
497
498/**
499 * 특정 컬럼을 가지고 있느냐?
500 *
501 * @param column 컬럼명
502 * @author 김흥수
503 * @since 2015-09-21
504 * @version 1.0
505 */
506DataSet.prototype.hasColumn = function(column) {
507	return this._columns.hasColumn(column);
508};
509
510/**
511 * 특정 컬럼에 포커스를 보낸다.
512 *
513 * @param column 컬럼명
514 * @returns boolean 해당 컬럼에 포커스를 보내는 것이 성공하면 true
515 * @author 김흥수
516 * @since 2015-09-21
517 * @version 1.0
518 */
519DataSet.prototype.focusTo = function(column) {
520	return this._binder.focusTo(column);
521};
522
523/**
524 * 정렬 정보를 clear 한다.
525 *
526 * @author 김흥수
527 * @since 2015-09-02
528 * @version 1.0
529 */
530DataSet.prototype.clearSort = function() {
531	this._sortInfo = [];
532};
533
534/**
535 * sort 정보 크기를 구한다.
536 *
537 * @author 김흥수
538 * @since 2015-09-02
539 * @version 1.0
540 */
541DataSet.prototype.sortSize = function() {
542	if (gf_IsObjNull(this._sortInfo))
543		return 0;
544	return this._sortInfo.length;
545};
546
547/**
548 * sort 정보를 추가한다.
549 *
550 * @param sortCol 정렬할 컬럼
551 * @param sortAsc boolean 오름차순이면 true 내림차순이면 false
552 * @author 김흥수
553 * @since 2015-09-02
554 * @version 1.0
555 */
556DataSet.prototype.addSort = function(sortCol, sortAsc) {
557	if (gf_IsObjNull(sortAsc))
558		sortAsc = true;
559	if (gf_IsObjNull(this._sortInfo)) {
560		this._sortInfo = [];
561	}
562	this._sortInfo.push({
563		"sortCol" : sortCol,
564		"sortAsc" : sortAsc
565	});
566};
567
568/**
569 * 정렬 정보에서 특정 정렬 정보를 지운다.
570 *
571 * @param id 삭제할 정렬 정보 인덱스 또는 정렬 정보 컬럼
572 * @author 김흥수
573 * @since 2015-09-02
574 * @version 1.0
575 */
576DataSet.prototype.removeSort = function(id) {
577	if (gf_IsObjNull(this._sortInfo)) {
578		return;
579	}
580	if (typeof id == "number") {
581		this._sortInfo.remove(id);
582	} else {
583		//var idx = this._sortInfo.findIndex(function(v) {
584		var idx = Array.prototype.findIndex.call(this._sortInfo,function(v) {
585			return v.sortCol == id;
586		});
587		if (idx >= 0) {
588			this._sortInfo.remove(idx);
589		}
590	}
591};
592
593/**
594 * 데이타셑 뷰를 정렬한다.
595 *
596 * @author 김흥수
597 * @since 2015-09-02
598 * @version 1.0
599 */
600DataSet.prototype.executeSort = function() {
601	if (gf_IsObjNull(this._sortInfo)) {
602		return;
603	}
604	var sortInfo = this._sortInfo;
605	var MAX_DATE = "99991231".toDate("YYYYMMDD").valueOf() + 1;
606	var that = this;
607
608	var normalSort = function(a, b, sortCol, sortChg) {
609		a = a.get(sortCol);
610		b = b.get(sortCol);
611		var nulla = gf_IsObjNull(a);
612		var nullb = gf_IsObjNull(b);
613		if (nulla && nullb)
614			return 0;
615		if (nulla)
616			return 1 * sortChg;
617		if (nullb)
618			return -1 * sortChg;
619		if (a == b)
620			return 0;
621		if (a < b)
622			return -1 * sortChg;
623		return 1 * sortChg;
624	};
625	var numberSort = function(a, b, sortCol, sortChg) {
626		a = a.get(sortCol);
627		b = b.get(sortCol);
628
629		var nulla = gf_IsObjNull(a);
630		var nullb = gf_IsObjNull(b);
631		if (nulla && nullb)
632			return 0;
633		if (nulla)
634			return 1 * sortChg;
635		if (nullb)
636			return -1 * sortChg;
637
638		a = gf_GetNumber(a);
639		b = gf_GetNumber(b);
640
641		if (a == b)
642			return 0;
643		if (a < b)
644			return -1 * sortChg;
645		return 1 * sortChg;
646	};
647	var decimalSort = function(a, b, sortCol, sortChg) {
648		a = a.get(sortCol);
649		b = b.get(sortCol);
650
651		var nulla = gf_IsObjNull(a);
652		var nullb = gf_IsObjNull(b);
653		if (nulla && nullb)
654			return 0;
655		if (nulla)
656			return 1 * sortChg;
657		if (nullb)
658			return -1 * sortChg;
659
660		a = gf_GetDecimal(a);
661		return a.compareTo(b) * sortChg;
662	};
663	var dateSort = function(a, b, sortCol, sortChg, fmt) {
664		a = a.get(sortCol);
665		b = b.get(sortCol);
666
667		var nulla = gf_IsObjNull(a);
668		var nullb = gf_IsObjNull(b);
669		if (nulla && nullb)
670			return 0;
671		if (nulla)
672			return 1 * sortChg;
673		if (nullb)
674			return -1 * sortChg;
675
676		a = a.toDate(fmt);
677		a = gf_IsObjNull(a) ? MAX_DATE : a.valueOf();
678		b = b.toDate(fmt);
679		b = gf_IsObjNull(b) ? MAX_DATE : b.valueOf();
680
681		if (a == b)
682			return 0;
683		if (a < b)
684			return -1 * sortChg;
685		return 1 * sortChg;
686	};
687
688	var f = function(a, b) {
689		for (var i = 0; i < sortInfo.length; i++) {
690			var sortCol = sortInfo[i].sortCol;
691			var sortAsc = sortInfo[i].sortAsc;
692			if (gf_IsObjNull(sortAsc))
693				sortAsc = true;
694			var sortChg = !sortAsc ? -1 : 1;
695			var fmt = that.fieldFormat(sortCol);
696			var dataType = that.fieldType(sortCol);
697			var cmp = 0;
698			if (dataType == DataSet.DataType.NUMBER) {
699				cmp = numberSort(a, b, sortCol, sortChg);
700			} else if (dataType == DataSet.DataType.DECIMAL) {
701				cmp = decimalSort(a, b, sortCol, sortChg);
702			} else if (dataType == DataSet.DataType.DATE) {
703				cmp = dateSort(a, b, sortCol, sortChg, fmt);
704			} else {
705				cmp = normalSort(a, b, sortCol, sortChg);
706			}
707			if (cmp != 0)
708				return cmp;
709		}
710		return 0;
711	};
712	this.view().sort(f);
713	this._binder.draw();
714};
715
716/**
717 * 데이타셋 뷰를 정렬한다.(단순 정렬)
718 *
719 * @param sortCol 정렬할 컬럼
720 * @param sortAsc 오름차순 정렬 여부(true : 오름차순 , false : 내림차순 )
721 * @author 김흥수
722 * @since 2015-09-02
723 * @version 1.0
724 */
725DataSet.prototype.sort = function(sortCol, sortAsc) {
726	if (gf_IsObjNull(sortCol)) {
727		this.executeSort();
728		return;
729	}
730	this.clearSort();
731	this.addSort(sortCol, sortAsc);
732	this.executeSort();
733};
734
735/**
736 * 데이타셋 뷰를 순회하며 그 결과를 배열로 만든다.
737 *
738 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
739 * @returns Array callback이 리턴한 값들의 배열
740 * @author 김흥수
741 * @since 2015-09-01
742 * @version 1.0
743 */
744DataSet.prototype.mapInView = function(callback) {
745	//return this.view().hvcMap(callback);
746	return Array.prototype.hvcMap.call(this.view(),callback);
747};
748
749/**
750 * 데이타셋 뷰를 순회하며 집계한다.
751 *
752 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(이전값,현재값,배열요소인덱스,배열) 이며 생략가능하다.
753 * @param init 초기값
754 * @returns callback이 마지막으로 return한 집계된 값
755 * @author 김흥수
756 * @since 2015-12-01
757 * @version 1.0
758 */
759DataSet.prototype.reduceInView = function(callback,init) {
760	return Array.prototype.reduce.call(this.view(),callback,init);
761};
762
763/**
764 * 데이타셋 뷰를 순회하며 max 집계한다.
765 *
766 * @param columnIdOrFunc 집계할 컬럼 또는 함수- 함수의 경우 함수 스펙은 function(dataSetRow) 이다.
767 * @param dataType DataSet.DataType 중 하나의 값이어야 한다. 만약 columnIdOrFunc 이 function 이면 기술해야 하며 생략하면 STRING으로 간주한다.
768 * @param fmt 날짜의 경우 저장 양식을 기술한다. function 이면 기술해야 하며 생략하면 "YYYYMMDD"으로 간주한다.
769 * @returns max 값
770 * @author 김흥수
771 * @since 2015-12-01
772 * @version 1.0
773 */
774DataSet.prototype.max = function(columnIdOrFunc,dataType,fmt) {
775	var f = function(curr) {
776		return curr.get(columnIdOrFunc);
777	};
778	if (typeof columnIdOrFunc === 'function') {
779		dataType = gf_Default(dataType,DataSet.DataType.STRING);
780		fmt = gf_Default(fmt,"YYYYMMDD");
781		f = function(curr){
782			return columnIdOrFunc(curr);
783		};
784	} else {
785		dataType = this.fieldType(columnIdOrFunc);
786		fmt = this.fieldFormat(columnIdOrFunc);
787	}
788	return this.reduceInView(function(prev,curr){
789		if(gf_IsObjNull(prev)) return f(curr);
790		if (dataType == DataSet.DataType.NUMBER) {
791			curr = f(curr);
792			if(gf_IsObjNull(curr)) return prev;
793			if(gf_IsObjNull(prev)) return curr;
794			prev = gf_GetNumber(prev);
795			curr = gf_GetNumber(curr);
796			return curr > prev ? curr.toString() : prev.toString();
797		} else if (dataType == DataSet.DataType.DECIMAL) {
798			curr = f(curr);
799			if(gf_IsObjNull(curr)) return prev;
800			if(gf_IsObjNull(prev)) return curr;
801			prev = gf_GetDecimal(prev);
802			curr = gf_GetDecimal(curr);
803			return curr.compareTo(prev) > 0 ? curr.toString() : prev.toString();
804		} else if (dataType == DataSet.DataType.DATE) {
805			curr = f(curr);
806			if(gf_IsObjNull(curr)) return prev;
807			if(gf_IsObjNull(prev)) return curr;
808			prev = prev.toDate(fmt);
809			curr = curr.toDate(fmt);
810			return curr > prev ? curr.format(fmt) : prev.format(fmt);
811		} else {
812			curr = f(curr);
813			return curr > prev ? curr : prev;
814		}
815	},null);
816};
817/**
818 * 데이타셋 뷰를 순회하며 min 집계한다.
819 *
820 * @param columnIdOrFunc 집계할 컬럼 또는 함수- 함수의 경우 함수 스펙은 function(dataSetRow) 이다.
821 * @param dataType DataSet.DataType 중 하나의 값이어야 한다. 만약 columnIdOrFunc 이 function 이면 기술해야 하며 생략하면 STRING으로 간주한다.
822 * @param fmt 날짜의 경우 저장 양식을 기술한다. function 이면 기술해야 하며 생략하면 "YYYYMMDD"으로 간주한다.
823 * @returns min 값
824 * @author 김흥수
825 * @since 2015-12-01
826 * @version 1.0
827 */
828DataSet.prototype.min = function(columnIdOrFunc,dataType,fmt) {
829	var f = function(curr) {
830		return curr.get(columnIdOrFunc);
831	};
832	if (typeof columnIdOrFunc === 'function') {
833		dataType = gf_Default(dataType,DataSet.DataType.STRING);
834		fmt = gf_Default(fmt,"YYYYMMDD");
835		f = function(curr){
836			return columnIdOrFunc(curr);
837		};
838	} else {
839		dataType = this.fieldType(columnIdOrFunc);
840		fmt = this.fieldFormat(columnIdOrFunc);
841	}
842	return this.reduceInView(function(prev,curr){
843		if(gf_IsObjNull(prev)) return f(curr);
844		if (dataType == DataSet.DataType.NUMBER) {
845			curr = f(curr);
846			if(gf_IsObjNull(curr)) return prev;
847			if(gf_IsObjNull(prev)) return curr;
848			prev = gf_GetNumber(prev);
849			curr = gf_GetNumber(curr);
850			return curr < prev ? curr.toString() : prev.toString();
851		} else if (dataType == DataSet.DataType.DECIMAL) {
852			curr = f(curr);
853			if(gf_IsObjNull(curr)) return prev;
854			if(gf_IsObjNull(prev)) return curr;
855			prev = gf_GetDecimal(prev);
856			curr = gf_GetDecimal(curr);
857			return curr.compareTo(prev) < 0 ? curr.toString() : prev.toString();
858		} else if (dataType == DataSet.DataType.DATE) {
859			curr = f(curr);
860			if(gf_IsObjNull(curr)) return prev;
861			if(gf_IsObjNull(prev)) return curr;
862			prev = prev.toDate(fmt);
863			curr = curr.toDate(fmt);
864			return curr < prev ? curr.format(fmt) : prev.format(fmt);
865		} else {
866			curr = f(curr);
867			return curr < prev ? curr : prev;
868		}
869	},null);
870};
871
872/**
873 * 데이타셋 뷰를 순회하며 sum 집계한다.
874 *
875 * @param columnIdOrFunc 집계할 컬럼 또는 함수- 함수의 경우 함수 스펙은 function(dataSetRow) 이다.
876 * @param dataType DataSet.DataType 중 하나의 값이어야 한다. 만약 columnIdOrFunc 이 function 이면 기술해야 하며 생략하면 STRING으로 간주한다.
877 * @param fmt 날짜의 경우 저장 양식을 기술한다. function 이면 기술해야 하며 생략하면 "YYYYMMDD"으로 간주한다.
878 * @returns sum 값
879 * @author 김흥수
880 * @since 2015-12-01
881 * @version 1.0
882 */
883DataSet.prototype.sum = function(columnIdOrFunc,dataType,fmt) {
884	var f = function(curr) {
885		return curr.get(columnIdOrFunc);
886	};
887	if (typeof columnIdOrFunc === 'function') {
888		dataType = gf_Default(dataType,DataSet.DataType.STRING);
889		fmt = gf_Default(fmt,"YYYYMMDD");
890		f = function(curr){
891			return columnIdOrFunc(curr);
892		};
893	} else {
894		dataType = this.fieldType(columnIdOrFunc);
895		fmt = this.fieldFormat(columnIdOrFunc);
896	}
897	return this.reduceInView(function(prev,curr){
898		if (dataType == DataSet.DataType.NUMBER) {
899			if(gf_IsObjNull(prev)) return f(curr);
900			curr = f(curr);
901			if(gf_IsObjNull(curr)) return prev;
902			if(gf_IsObjNull(prev)) return curr;
903			prev = gf_GetNumber(prev);
904			curr = gf_GetNumber(curr);
905			return (prev + curr).toString();
906		} else if (dataType == DataSet.DataType.DECIMAL) {
907			if(gf_IsObjNull(prev)) return f(curr);
908			curr = f(curr);
909			if(gf_IsObjNull(curr)) return prev;
910			if(gf_IsObjNull(prev)) return curr;
911			prev = gf_GetDecimal(prev);
912			curr = gf_GetDecimal(curr);
913			return prev.add(curr).toString();
914		} else if (dataType == DataSet.DataType.DATE) {
915			return null;
916		} else {
917			return null;
918		}
919	},null);
920};
921
922/**
923 * 데이타셋 뷰를 순회하며 count 집계한다.(null 인 값은 집계 제외)
924 *
925 * @param columnIdOrFunc 집계할 컬럼 또는 함수- 함수의 경우 함수 스펙은 function(dataSetRow) 이다.
926 * @returns count 값
927 * @author 김흥수
928 * @since 2015-12-01
929 * @version 1.0
930 */
931DataSet.prototype.count = function(columnIdOrFunc) {
932	var f = function(curr) {
933		return curr.get(columnIdOrFunc);
934	};
935	if (typeof columnIdOrFunc === 'function') {
936		f = function(curr){
937			return columnIdOrFunc(curr);
938		};
939	}
940	return this.reduceInView(function(prev,curr){
941		if(gf_IsObjNull(columnIdOrFunc)) {
942			return prev + 1;
943		}
944		curr = f(curr);
945		if(! gf_IsNull(curr)) {
946			return prev + 1;
947		}
948		return prev;
949	},0);
950};
951
952/**
953 * 데이타셋 뷰를 순회하며 avg 집계한다.
954 *
955 * @param columnIdOrFunc 집계할 컬럼 또는 함수- 함수의 경우 함수 스펙은 function(dataSetRow) 이다.
956 * @param dataType DataSet.DataType 중 하나의 값이어야 한다. 만약 columnIdOrFunc 이 function 이면 기술해야 하며 생략하면 STRING으로 간주한다.
957 * @param fmt 날짜의 경우 저장 양식을 기술한다. function 이면 기술해야 하며 생략하면 "YYYYMMDD"으로 간주한다.
958 * @returns avg 값
959 * @author 김흥수
960 * @since 2015-12-01
961 * @version 1.0
962 */
963DataSet.prototype.avg = function(columnIdOrFunc,dataType,fmt) {
964	var f = function(curr) {
965		return curr.get(columnIdOrFunc);
966	};
967	if (typeof columnIdOrFunc === 'function') {
968		dataType = gf_Default(dataType,DataSet.DataType.STRING);
969		fmt = gf_Default(fmt,"YYYYMMDD");
970		f = function(curr){
971			return columnIdOrFunc(curr);
972		};
973	} else {
974		dataType = this.fieldType(columnIdOrFunc);
975		fmt = this.fieldFormat(columnIdOrFunc);
976	}
977	var cnt = 0;
978	var sum = null;
979	if (dataType == DataSet.DataType.NUMBER) {
980		sum = 0;
981	} else if (dataType == DataSet.DataType.DECIMAL) {
982		sum = gf_GetDecimal("0");
983	}
984	function div1(s,cnt) {
985		if(cnt == 0) return ;
986		return (s / cnt).toString();
987	}
988	function div2(s,cnt) {
989		if(cnt == 0) return "";
990		return s.divide(cnt).toString();
991	}
992	return this.reduceInView(function(prev,curr){
993		if (dataType == DataSet.DataType.NUMBER) {
994			curr = f(curr);
995			if(gf_IsObjNull(curr)) {
996				return div1(sum,cnt);
997			}
998			sum += gf_GetNumber(curr);
999			cnt ++;
1000			return div1(sum,cnt);
1001		} else if (dataType == DataSet.DataType.DECIMAL) {
1002			curr = f(curr);
1003			if(gf_IsObjNull(curr)) {
1004				return div2(sum,cnt);
1005			}
1006			sum = sum.add(gf_GetDecimal(curr));
1007			cnt ++;
1008			return div2(sum,cnt);
1009		} else if (dataType == DataSet.DataType.DATE) {
1010			return null;
1011		} else {
1012			return null;
1013		}
1014	},null);
1015};
1016
1017/**
1018 * 데이타셋 뷰를 순회하며 그 결과를 배열로 만든다.
1019 *
1020 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1021 * @param condf <pre>
1022 *     콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다. 리턴은
1023 *     boolean 이며 true를 리턴하는 요소만 최종 리턴 배열에 포함된다. 이 요소가 생략되거나 null이면 모든
1024 *     요소에 대하여 callback이 호출된다.
1025 *            </pre
1026 * @returns Array callback이 리턴한 값들의 배열
1027 * @author 김흥수
1028 * @since 2015-09-01
1029 * @version 1.0
1030 */
1031DataSet.prototype.mapIfInView = function(callback, condf) {
1032	//return this.view().mapIf(callback, condf);
1033	return Array.prototype.mapIf.call(this.view(),callback, condf);
1034};
1035
1036/**
1037 * 데이타셋 뷰를 순회한다.
1038 *
1039 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1040 * @author 김흥수
1041 * @since 2015-09-01
1042 * @version 1.0
1043 */
1044DataSet.prototype.forEachInView = function(callback) {
1045	//this.view().forEachL(callback);
1046	Array.prototype.forEachL.call(this.view(),callback);
1047};
1048
1049/**
1050 * 데이타셋 뷰를 순회한다. 단 중간에 중단 가능하다. callback이 true를 return하면 중단한다.
1051 *
1052 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다. 리턴은 boolean 또는 없다.
1053 * @author 김흥수
1054 * @since 2015-09-01
1055 * @version 1.0
1056 */
1057DataSet.prototype.forEachStoppableInView = function(callback) {
1058	//this.view().forEachStoppable(callback);
1059	Array.prototype.forEachStoppable.call(this.view(),callback);
1060};
1061
1062/**
1063 * 데이타셋을 순회한다.
1064 *
1065 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1066 * @author 김흥수
1067 * @since 2015-09-01
1068 * @version 1.0
1069 */
1070DataSet.prototype.forEachInRows = function(callback) {
1071	//this._rows.forEachL(callback);
1072	Array.prototype.forEachL.call(this._rows,callback);
1073};
1074
1075/**
1076 * 데이타셋을 순회한다. 단 중간에 중단 가능하다. callback이 true를 return하면 중단한다.
1077 *
1078 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다. 리턴은 boolean 또는 없다.
1079 * @author 김흥수
1080 * @since 2015-09-01
1081 * @version 1.0
1082 */
1083DataSet.prototype.forEachStoppableInRows = function(callback) {
1084	//this._rows.forEachStoppable(callback);
1085	Array.prototype.forEachStoppable.call(this._rows,callback);
1086};
1087
1088/**
1089 * 데이타셑을 순회하며 그 결과를 배열로 만든다.
1090 *
1091 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1092 * @returns Array callback이 리턴한 값들의 배열
1093 * @author 김흥수
1094 * @since 2015-09-01
1095 * @version 1.0
1096 */
1097DataSet.prototype.mapInRows = function(callback) {
1098	//return this._rows.hvcMap(callback);
1099	return Array.prototype.hvcMap.call(this._rows,callback);
1100};
1101
1102/**
1103 * 데이타셑을 순회하며 집계한다.
1104 *
1105 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(이전값,현재값,배열요소인덱스,배열) 이며 생략가능하다.
1106 * @param init 초기값
1107 * @returns callback이 마지막으로 return한 집계된 값
1108 * @author 김흥수
1109 * @since 2015-12-01
1110 * @version 1.0
1111 */
1112DataSet.prototype.reduceInRows = function(callback,init) {
1113	return Array.prototype.reduce.call(this._rows,callback,init);
1114};
1115
1116/**
1117 * 데이타셑을 순회하며 그 결과를 배열로 만든다.
1118 *
1119 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1120 * @param condf <pre>
1121 *     콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다. 리턴은
1122 *     boolean 이며 true를 리턴하는 요소만 최종 리턴 배열에 포함된다. 이 요소가 생략되거나 null이면 모든
1123 *     요소에 대하여 callback이 호출된다.
1124 *            </pre>
1125 * @returns Array callback이 리턴한 값들의 배열
1126 * @author 김흥수
1127 * @since 2015-09-01
1128 * @version 1.0
1129 */
1130DataSet.prototype.mapIfInRows = function(callback, condf) {
1131	//return this._rows.mapIf(callback, condf);
1132	return Array.prototype.mapIf.call(this._rows,callback, condf);
1133};
1134
1135/**
1136 * 삭제된 것으로 표기된 행에대하여 순회를 한다.
1137 *
1138 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1139 * @author 김흥수
1140 * @since 2015-09-01
1141 * @version 1.0
1142 */
1143DataSet.prototype.forEachInDeleted = function(callback) {
1144	//this._deletedRows.forEachL(callback);
1145	Array.prototype.forEachL.call(this._deletedRows,callback);
1146};
1147
1148/**
1149 * 삭제된 것으로 표기된 행에대하여 순회를 한다. 단 중간에 중단이 가능하다. callback의 return 값이 true이면 중단된다.
1150 *
1151 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다. 리턴은 boolean 또는 없다.
1152 * @author 김흥수
1153 * @since 2015-09-01
1154 * @version 1.0
1155 */
1156DataSet.prototype.forEachStoppableInDeleted = function(callback) {
1157	//this._deletedRows.forEachStoppable(callback);
1158	Array.prototype.forEachStoppable.call(this._deletedRows,callback);
1159};
1160
1161/**
1162 * 삭제된 것으로 표기된 행에대하여 순회하며 그 결과를 배열로 만든다.
1163 *
1164 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1165 * @author 김흥수
1166 * @since 2015-09-01
1167 * @version 1.0
1168 */
1169DataSet.prototype.mapInDeleted = function(callback) {
1170	//return this._deletedRows.hvcMap(callback);
1171	return Array.prototype.hvcMap.call(this._deletedRows,callback);
1172};
1173
1174/**
1175 * 데이타셋 뷰를 순회한다.
1176 *
1177 * @param callback 콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다.
1178 * @param condf <pre>
1179 *     콜백 함수이다. 콜백함수의 스펙은 function(배열요소값,배열요소인덱스,배열) 이며 생략가능하다. 리턴은
1180 *     boolean 이며 true를 리턴하는 요소만 최종 리턴 배열에 포함된다. 이 요소가 생략되거나 null이면 모든
1181 *     요소에 대하여 callback이 호출된다.
1182 *            </pre>
1183 * @returns Array callback이 리턴한 값들의 배열
1184 * @author 김흥수
1185 * @since 2015-09-01
1186 * @version 1.0
1187 */
1188DataSet.prototype.mapIfInDeleted = function(callback, condf) {
1189	//return this._deletedRows.mapIf(callback, condf);
1190	return Array.prototype.mapIf.call(this._deletedRows,callback, condf);
1191};
1192
1193/**
1194 * 데이타셋에 바인딩된 ui들의 변경사항 중 데이타셋에 반영되지 않은 것이 있으면 반영한다.
1195 *
1196 * @author 김흥수
1197 * @since 2015-09-01
1198 * @version 1.0
1199 */
1200DataSet.prototype.applyEdit = function() {
1201	this._binder.applyEdit();
1202};
1203
1204/**
1205 * 데이타셋에 바인딩된 ui들의 모든 자료를 데이타셋에 반영함
1206 *
1207 * @author 김흥수
1208 * @since 2015-09-01
1209 * @version 1.0
1210 */
1211DataSet.prototype.applyFromUi = function() {
1212	this._binder.applyAll();
1213};
1214
1215/**
1216 * 데이터셑에 이벤트를 설정함.
1217 *
1218 * @param eventName 등록할 이벤트 이름
1219 * @param handler 등록할 이벤트 핸들러. 핸들러의 스펙은 function(eventArgs) 이다.
1220 * @author 김흥수
1221 * @since 2015-08-28
1222 * @version 1.0
1223 */
1224DataSet.prototype.bindEvent = function(eventName, handler) {
1225	var ev = this._events[eventName];
1226
1227	if (gf_IsObjNull(ev))
1228		throw "이벤트가 존재하지 않습니다. (" + eventName + ")";
1229	if (ev.handlers.indexOf(handler) >= 0)
1230		return; // 이미 등록된 이벤트는 중복 등록되지 않아요.
1231	ev.handlers.push(handler);
1232};
1233
1234/**
1235 * 데이터셑에 이벤트를 설정 해제함.
1236 *
1237 * @param eventName 등록 해제할 이벤트 이름 생략하면 모든 이벤트를 해제한다.
1238 * @param handler 등록 해제할 이벤트 핸들러. 생략하면 해당 이벤트의 모든 핸들러를 해제한다.
1239 * @author 김흥수
1240 * @since 2015-08-28
1241 * @version 1.0
1242 */
1243DataSet.prototype.unbindEvent = function(eventName, handler) {
1244	if (gf_IsObjNull(eventName)) {
1245		//this._events.forEachL(function(ev) {
1246		Array.prototype.forEachL.call(this._events,function(ev) {
1247			ev.handlers.clear();
1248		});
1249		return;
1250	}
1251	var ev = this._events[eventName];
1252	if (gf_IsObjNull(ev))
1253		throw "이벤트가 존재하지 않습니다. (" + eventName + ")";
1254	if (gf_IsObjNull(handler)) {
1255		ev.handlers.clear();
1256	}
1257	var idx = ev.handlers.indexOf(handler);
1258
1259	if (idx >= 0)
1260		ev.handlers.remove(idx);
1261};
1262
1263/**
1264 * 데이터셑에서 이벤트를 발생시킴
1265 *
1266 * @param eventName 발생시킬 이벤트
1267 * @param eventArgs
1268 *            이벤트 인자. 이벤트 종류에 따라 다르지만 기본적으로 prevent와 lastReturn 라는 속성을 가지며
1269 *            prevent 에 true를 설정하면 이벤트 수행이 중단된다. 또한 lastReturn은 이벤트 핸들러 체인 상의 직전
1270 *            핸들러가 리턴한 값을 가지고 있다.
1271 * @author 김흥수
1272 * @since 2015-08-28
1273 * @version 1.0
1274 */
1275DataSet.prototype.fireEvent = function(eventName, eventArgs) {
1276	var ev = this._events[eventName];
1277	if (gf_IsObjNull(ev))
1278		throw "이벤트가 존재하지 않습니다. (" + eventName + ")";
1279
1280	if (gf_IsObjNull(eventArgs)) {
1281		eventArgs = {
1282			"prevent" : false,
1283			"dataSet" : this
1284		};
1285	} else {
1286		eventArgs.prevent = false;
1287		eventArgs.dataSet = this;
1288	}
1289	eventArgs.lastReturn = null;
1290
1291	//ev.handlers.forEachStoppable(function(fct) {
1292	Array.prototype.forEachStoppable.call(ev.handlers,function(fct) {
1293		this, eventArgs.lastReturn = fct.call(null, eventArgs);
1294		if (eventArgs.prevent)
1295			return true;
1296	}, this);
1297
1298	return eventArgs.lastReturn;
1299
1300};
1301
1302/**
1303 * 데이터셑에서 cell의 값이 변경된 경우 발생하는 이벤트
1304 *
1305 * @param rowIndex 변경된 행의 view 기반의 행 인덱스 필터되어 가려진 데이타 행의 경우는 이 이벤트가 발생하지 않는다.
1306 * @param columnName 변경된 컬럼명
1307 * @param oldValue 변경 전 값
1308 * @param newValue 변경 후 값
1309 * @author 김흥수
1310 * @since 2015-08-28
1311 * @version 1.0
1312 */
1313DataSet.prototype.fireValueChanged = function(rowIndex, columnName, oldValue,
1314		newValue) {
1315	if (this.suppressEvent)
1316		return;
1317	this._binder.posDraw(rowIndex, columnName, newValue);
1318	this.fireEvent("valueChanged", {
1319		"rowIndex" : rowIndex,
1320		"columnName" : columnName,
1321		"oldValue" : oldValue,
1322		"newValue" : newValue
1323	});
1324};
1325
1326/**
1327 * 데이터셑에서 행위치가 변경되기 직전 발생하는 이벤트
1328 *
1329 * @param oldRowIndex 이동 전 행 인덱스
1330 * @param newRowIndex 이동하고자하는 목적지 행 인덱스
1331 * @author 김흥수
1332 * @since 2015-10-01
1333 * @version 1.0
1334 */
1335DataSet.prototype.fireRowPositionChanging = function(oldRowIndex, newRowIndex) {
1336	if (this.suppressEvent)
1337		return true;
1338	if(!this.checkChildrenUpdated()) return false;
1339	return this.fireEvent("rowPositionChanging", {
1340		"oldRowIndex" : oldRowIndex,
1341		"newRowIndex" : newRowIndex
1342	});
1343};
1344
1345/**
1346 * 데이터셑에서 행위치가 변경되면 발생하는 이벤트
1347 *
1348 * @param oldRowIndex 이동 전 행 인덱스
1349 * @param newRowIndex 이동하는 목적지 행 인덱스
1350 * @author 김흥수
1351 * @since 2015-08-31
1352 * @version 1.0
1353 */
1354DataSet.prototype.fireRowPositionChanged = function(oldRowIndex, newRowIndex) {
1355	if (this.suppressEvent)
1356		return;
1357	this._binder.activeRow(newRowIndex);
1358	this.retrieveChildren(newRowIndex);
1359	this.fireEvent("rowPositionChanged", {
1360		"oldRowIndex" : oldRowIndex,
1361		"newRowIndex" : newRowIndex
1362	});
1363};
1364
1365/**
1366 * 데이터셑에서 행이 삽입될 때 타는 이벤트 ( 만약 beforeInsert가 return true 이면 삽입 행위가 취소된다.
1367 *
1368 * @param rowIndex 행이 삽입되는 위치 , 이 위치보다 크거나 같은 행위치는 한 행씩 뒤로 밀려난다.
1369 * @param dataSetRow 삽입되는 행의 DataSetRow 자료
1370 * @author 김흥수
1371 * @since 2015-08-31
1372 * @version 1.0
1373 */
1374DataSet.prototype.fireBeforeInsert = function(rowIndex, dataSetRow) {
1375	if (this.suppressEvent)
1376		return true;
1377	return this.fireEvent("beforeInsert", {
1378		"rowIndex" : rowIndex,
1379		"dataSetRow" : dataSetRow
1380	});
1381};
1382
1383/**
1384 * 데이터셑에서 행이 삭제될 때 타는 이벤트 ( 만약 beforeDelete가 return true 이면 삭제 행위가 취소된다. )
1385 *
1386 * @param rowIndex 행이 삭제되는 위치
1387 * @param dataSetRow 삭제되는 행의 DataSetRow 자료
1388 * @author 김흥수
1389 * @since 2015-08-31
1390 * @version 1.0
1391 */
1392DataSet.prototype.fireBeforeDelete = function(rowIndex, dataSetRow) {
1393	if (this.suppressEvent)
1394		return;
1395	return this.fireEvent("beforeDelete", {
1396		"rowIndex" : rowIndex,
1397		"dataSetRow" : dataSetRow
1398	});
1399};
1400
1401/**
1402 * 데이터셑에서 행이 삽입될 때 타는 이벤트
1403 *
1404 * @param rowIndex 행이 삽입되는 위치 , 이 위치보다 크거나 같은 행위치는 한 행씩 뒤로 밀려난다.
1405 * @param dataSetRow 삽입되는 행의 DataSetRow 자료
1406 * @param prevDataSetRow 삽입되는 행 직전 행의 DataSetRow 자료
1407 * @author 김흥수
1408 * @since 2015-08-31
1409 * @version 1.0
1410 */
1411DataSet.prototype.fireRowInserted = function(rowIndex, dataSetRow,
1412		prevDataSetRow) {
1413	if (this.suppressEvent)
1414		return;
1415	this._binder.posAdd(rowIndex, dataSetRow, prevDataSetRow);
1416	this.fireEvent("rowInserted", {
1417		"rowIndex" : rowIndex,
1418		"dataSetRow" : dataSetRow,
1419		"prevDataSetRow" : prevDataSetRow
1420	});
1421};
1422
1423/**
1424 * 데이터셑에서 행이 삭제될 때 타는 이벤트
1425 *
1426 * @param rowIndex 행이 삭제되는 위치
1427 * @param dataSetRow 삭제되는 행의 DataSetRow 자료
1428 * @author 김흥수
1429 * @since 2015-08-31
1430 * @version 1.0
1431 */
1432DataSet.prototype.fireRowDeleted = function(rowIndex, dataSetRow) {
1433	if (this.suppressEvent)
1434		return;
1435	this._binder.posDel(rowIndex, dataSetRow);
1436	this.fireEvent("rowDeleted", {
1437		"rowIndex" : rowIndex,
1438		"dataSetRow" : dataSetRow
1439	});
1440};
1441
1442/**
1443 * 데이터셑에서 두 행의 자료가 서로 바뀐다.
1444 *
1445 * @param fromRow 서로 바뀔 첫 행
1446 * @param toRow 서로 바뀔 두번째 행
1447 * @author 김흥수
1448 * @since 2015-08-31
1449 * @version 1.0
1450 */
1451DataSet.prototype.fireRowSwapped = function(fromRow, toRow) {
1452	if (this.suppressEvent)
1453		return;
1454	this._binder.draw();
1455	this.fireEvent("rowSwapped", {
1456		"fromRow" : fromRow,
1457		"toRow" : toRow
1458	});
1459};
1460
1461/**
1462 * 데이터셑에 Position을 설정함.
1463 *
1464 * @param pos 행의 인덱스
1465 * @param isMove boolean 현재행과 이동하고자 하는 행이 같은 경우라도 강제로 rowPosition이 변경되게 하는 경우에 true로 설정한다. 기본값은 false
1466 * @author Jun.
1467 * @since 2013-03-28
1468 * @version 1.0
1469 */
1470DataSet.prototype.setPosition = function(pos, isMove) {
1471	if (gf_IsObjNull(pos))
1472		throw "행 위치가 잘못되었습니다.(null)";
1473	if (pos >= this.size())
1474		throw "행 위치가 잘못되었습니다.";
1475	if (pos < -1)
1476		pos = -1;
1477	isMove = typeof (isMove) == "undefined" ? false : isMove;
1478	if (this._pos == pos && !isMove)
1479		return;
1480	var oldPos = this._pos;
1481	if (!this.suppressEvent) {
1482		var acceptChange = this.fireRowPositionChanging(oldPos, pos);
1483		if (gf_IsObjNull(acceptChange)) {
1484			acceptChange = true;
1485		}
1486		if (!acceptChange) {
1487			var taht = this;
1488			setTimeout(function() {
1489				taht.suppressEvent = true;
1490				try {
1491					taht._binder.activeRow(oldPos, true);
1492				} catch (e) {gf_Trace(e.toString());}
1493				taht.suppressEvent = false;
1494			}, 0);
1495			return;
1496		}
1497	}
1498	this._pos = pos;
1499	if (!this.suppressEvent) {
1500		this.fireRowPositionChanged(oldPos, pos);
1501	}
1502};
1503
1504/**
1505 * 데이터셑에 Position을 출력함.
1506 *
1507 * @return pos 현재 행 인덱스
1508 * @author Jun.
1509 * @since 2013-03-28
1510 * @version 1.0
1511 */
1512DataSet.prototype.getPosition = function() {
1513	return this._pos;
1514};
1515
1516/**
1517 * 객체배열을 데이터셑에 임포트함.
1518 *
1519 * @param list 객체 배열
1520 * @param useClone 각각의 행의 행 데이타를 복제할지 여부를 결정한다. 기본값은 (false)
1521 * @author Jun.
1522 * @since 2013-03-28
1523 * @version 1.0
1524 */
1525DataSet.prototype.setAllData = function(list,useClone) {
1526	useClone = gf_Default(useClone,false);
1527	this.clear();
1528	if (list == null) {
1529		return;
1530	}
1531
1532	this.suppressEvent = true;
1533	Array.prototype.forEachL.call(list,function(v, i) {
1534		this.getRowRef(this.add(v,useClone)).apply();
1535	}, this);
1536	this.suppressEvent = false;
1537	this._filtering(true);
1538	this._binder.displayNodata();
1539	if((! gf_IsObjNull(this._children) && this._children.length > 0 && this.size() > 0) || this._formBind && this.size() > 0 ) {
1540		this.setPosition(0);
1541	} else {
1542		this.setPosition(-1, true);
1543	}
1544};
1545
1546/**
1547 * JSONObject 객체를 받아 마지막 Row 다음에 Row를 추가함
1548 *
1549 * @param obj 행 데이타 객체 (json)
1550 * @param useClone obj를 복제할지 여부를 결정한다. 기본값은 (false)
1551 * @returns index 추가된 행의 인덱스
1552 * @author Jun.
1553 * @since 2013-03-28
1554 * @version 1.0
1555 */
1556DataSet.prototype.add = function(obj,useClone) {
1557
1558	useClone = gf_Default(useClone,false);
1559	var index = this.size();
1560	return this.insert(index, obj);
1561};
1562
1563/**
1564 * JSONObject 객체를 받아 임의의 지정된 위치에 Row를 삽입함
1565 *
1566 * @param index 삽입될 행의 위치 (행 인덱스)
1567 * @param obj 행 데이타 객체 (json)
1568 * @param useClone obj를 복제할지 여부를 결정한다. 기본값은 (false)
1569 * @returns index 삽입된 행의 인덱스
1570 * @author Jun.
1571 * @since 2013-03-28
1572 * @version 1.0
1573 */
1574DataSet.prototype.insert = function(index, obj,useClone) {
1575	useClone = gf_Default(useClone,false);
1576	var rowId = this.newId();
1577	if (gf_IsObjNull(obj)) {
1578		obj = {};
1579	}
1580	if(useClone) {
1581		obj = DataSet.Util.objectClone(obj);
1582	}
1583	obj[DataSet.RowIdColumn] = rowId;
1584	var dataSetRow = new DataSet.DataSetRow(obj, this);
1585	var prevDataSetRow = null;
1586	dataSetRow.setStatus(DataSet.DataSetStatus.INSERT);
1587
1588	if (index > this.size()) {
1589		index = this.size();
1590	} else if (index < 0) {
1591		index = 0;
1592	}
1593	if (! gf_Default(this.fireBeforeInsert(index, dataSetRow),true) )
1594		return -1;
1595	if (gf_IsObjNull(this._view)) {
1596		if (index < this.size()) {
1597			prevDataSetRow = this.getRowRef(index - 1);
1598			//this._rows.insert(index, dataSetRow);
1599			Array.prototype.insert.call(this._rows,index, dataSetRow);
1600		} else {
1601			this._rows.push(dataSetRow);
1602		}
1603	} else {
1604		if (index < this.size()) {
1605			prevDataSetRow = this._view[index - 1];
1606			var rowIndex = this.getRowIndex(this._view[index]);
1607			//this._view.insert(index, dataSetRow);
1608			Array.prototype.insert.call(this._view,index, dataSetRow);
1609			//this._rows.insert(rowIndex, dataSetRow);
1610			Array.prototype.insert.call(this._rows,rowIndex, dataSetRow);
1611		} else {
1612			this._view.push(dataSetRow);
1613			this._rows.push(dataSetRow);
1614		}
1615	}
1616
1617	if (!this.suppressEvent) {
1618		this.fireRowInserted(index, dataSetRow, prevDataSetRow);
1619		this.setPosition(index, true);
1620	}
1621	this._binder.displayNodata();
1622	return index;
1623};
1624
1625/**
1626 * index를 받아 해당 데이터 로우를 삭제함. (기존에 존재한 Row는 상태값을 DELETE로 변경후 deleteRow에 삽입하고,
1627 * add된 데이터로우는 그냥 소멸시킴)
1628 *
1629 * @param index index는 총 4가지가 가능하다.
1630 *        1) Number : 행의 인덱스
1631 *        2) DataSetRow : 행 그자체 객체
1632 *        3) [Number] : 행 인덱스의 배열
1633 *        4) [DataSetRow] : 행 그자체의 배열
1634 * @param ignoreDelete boolean 이 값이 true이면 행 삭제 버퍼로 옮겨지지 않고 지워만 진다.(즉 완전히 지워지지만 DB로는 행의 삭제 사실이 전달되지 않는다.) 기본값은 false
1635 * @author Jun.
1636 * @since 2013-03-28
1637 * @version 1.0
1638 */
1639DataSet.prototype.remove = function(index, ignoreDelete) {
1640
1641	if ( gf_IsNull(ignoreDelete) ) {
1642		ignoreDelete = false;
1643	}
1644
1645	if ($.isArray(index)) {
1646		if (index.length < 1)
1647			return;
1648		if (!(index[0] instanceof DataSet.DataSetRow)) {
1649			index.sort(function(a, b) {
1650				var c = a - b;
1651				if (c > 0)
1652					return -1;
1653				else if (c == 0)
1654					return 0;
1655				else
1656					return 1;
1657			});
1658		}
1659		var that = this;
1660		//index.forEachL(function(i) {
1661		Array.prototype.forEachL.call(index,function(i) {
1662			that._removeEachRow(i,ignoreDelete);
1663		});
1664	} else {
1665		this._removeEachRow(index,ignoreDelete);
1666	}
1667	var newIndex = this._pos;
1668	if (this.size() < 1) {
1669		newIndex = -1;
1670	} else {
1671		if (index <= newIndex) {
1672			newIndex--;
1673		}
1674		if (newIndex < 0)
1675			newIndex = 0;
1676		if (newIndex >= this.size())
1677			newIndex = this.size() - 1;
1678	}
1679
1680	this.setPosition(newIndex, true);
1681};
1682
1683/**
1684 * 내부 함수입니다. 외부에서는 사용 불가.
1685 * index를 받아 해당 데이터 로우를 삭제함. (기존에 존재한 Row는 상태값을 DELETE로 변경후 deleteRow에 삽입하고, add된 데이터로우는 그냥 소멸시킴)
1686 *
1687 * @param index 행 인덱스 또는 DataSetRow
1688 * @param ignoreDelete boolean 이 값이 true이면 행 삭제 버퍼로 옮겨지지 않고 지워만 진다. 기본값은 false
1689 * @author Jun.
1690 * @since 2013-03-28
1691 * @version 1.0
1692 */
1693DataSet.prototype._removeEachRow = function(index, ignoreDelete) {
1694
1695	var dataSetRow = null;
1696	var rowIndex = -1;
1697
1698	if (index instanceof DataSet.DataSetRow) {
1699		dataSetRow = index;
1700		index = this.getRowIndexInView(dataSetRow);
1701	} else {
1702		dataSetRow = this.getRowRefInView(index);
1703	}
1704
1705	if (gf_IsObjNull(dataSetRow)) {
1706		throw "삭제할 행을 발견할 수 없습니다.";
1707	}
1708
1709	if (this.fireBeforeDelete(index, dataSetRow)) {
1710		return;
1711	}
1712	if (dataSetRow.getStatus() != DataSet.DataSetStatus.INSERT) {
1713		dataSetRow.remove();
1714		// 이경우 삭제로그를 남기지 않는다.
1715		if ( !ignoreDelete ) {
1716			this._deletedRows.push(dataSetRow);
1717		}
1718	}
1719
1720	if (gf_IsObjNull(this._view)) {
1721		rowIndex = index;
1722	} else {
1723		rowIndex = this.getRowIndex(dataSetRow);
1724		this._view.remove(index);
1725	}
1726
1727	this._rows.remove(rowIndex);
1728	if (rowIndex < 0)
1729		return;
1730	this.fireRowDeleted(index, dataSetRow);
1731
1732};
1733
1734
1735/**
1736 * 모든 데이터를 제거하고 데이터셑을 초기화함.
1737 *
1738 * @author Jun.
1739 * @since 2013-03-28
1740 * @version 1.0
1741 */
1742DataSet.prototype.clear = function() {
1743	this._filter = null;
1744	this._rows = [];
1745	this._lastId = -1;
1746	this._deletedRows = [];
1747	this._view = null;
1748	this.setPosition(-1);
1749	this._binder.draw();
1750	//if(! gf_IsObjNull(this._children))  this._children.forEachL(function(child){ child.dataSet.clear(); });
1751	if(! gf_IsObjNull(this._children))  Array.prototype.forEachL.call( this._children,function(child){ child.dataSet.clear(); });
1752};
1753
1754/**
1755 * 특정 행 인덱스의 DataSetRow를 view에서 찾아서 리턴한다.
1756 *
1757 * @param rowIdx
1758 * @returns DataSetRow 해당 위치의 데이타셑행
1759 * @author 김흥수
1760 * @since 2015-08-25
1761 * @version 1.0
1762 */
1763DataSet.prototype.getRowRefInView = function(rowIdx) {
1764	if (gf_IsObjNull(rowIdx)) {
1765		rowIdx = this.getPosition();
1766	}
1767	if (rowIdx >= this.size()) {
1768		throw "행의 범위가 벗어났습니다.";
1769	}
1770	if (rowIdx < 0)
1771		return null;
1772	var r = gf_IsObjNull(this._view) ? this._rows : this._view;
1773	return r[rowIdx];
1774
1775};
1776
1777/**
1778 * 특정 행 인덱스의 DataSetRow를 rows에서 찾아서 리턴한다.
1779 *
1780 * @param rowIdx
1781 * @returns DataSetRow 해당 위치의 데이타셑행
1782 * @author 김흥수
1783 * @since 2015-08-25
1784 * @version 1.0
1785 */
1786DataSet.prototype.getRowRef = function(rowIdx) {
1787	if (rowIdx >= this.rowSize()) {
1788		throw "행의 범위가 벗어났습니다.";
1789	}
1790	return this._rows[rowIdx];
1791
1792};
1793
1794/**
1795 * 데이타셑의 DataSetRow를 이용하여 해당 행이 있는 행 인덱스를 view 안에서 구한다.
1796 *
1797 * @param dataRow 행의 DataSetRow 객체
1798 * @returns Number 해당 행의 행 인덱스
1799 * @author 김흥수
1800 * @since 2015-08-25
1801 * @version 1.0
1802 */
1803DataSet.prototype.getRowIndexInView = function(dataRow) {
1804	var r = gf_IsObjNull(this._view) ? this._rows : this._view;
1805	return r.indexOf(dataRow);
1806
1807};
1808
1809/**
1810 * 데이타셑의 DataSetRow를 이용하여 해당 행이 있는 행 인덱스를 rows 안에서 구한다.
1811 *
1812 * @param dataRow
1813 * @returns Number 해당 행의 행 인덱스
1814 * @author 김흥수
1815 * @since 2015-08-25
1816 * @version 1.0
1817 */
1818DataSet.prototype.getRowIndex = function(dataRow) {
1819	return this._rows.indexOf(dataRow);
1820};
1821
1822/**
1823 * 특정 Row의 Column의 데이터를 변경함
1824 *
1825 * @param index 행인덱스
1826 * @param key 컬럼명
1827 * @param value 수정할 컬럼 값
1828 * @author Jun.
1829 * @since 2013-03-28
1830 * @version 1.0
1831 */
1832DataSet.prototype.set = function(index, key, value) {
1833	if (!this._columns.hasColumn(key)) // 컬럼이 정의되지 않았거나 컬럼에 해당 키가 존재하지 않을경우
1834		return;
1835	this.getRowRefInView(index).set(key, value, index);
1836};
1837
1838/**
1839 * 특정 Row의 위치를 이동시킴.
1840 *
1841 * @param from 이동할 행 인덱스
1842 * @param to 이동해서 옮겨 갈 곳의 행 인덱스
1843 * @author Jun.
1844 * @since 2013-03-28
1845 * @version 1.0
1846 */
1847DataSet.prototype.swap = function(from, to) {
1848	if (this.size() < 1)
1849		throw "이동할 데이타가 없습니다.";
1850	from = this.getNearIndex(from);
1851	to = this.getNearIndex(to);
1852
1853	if (gf_IsObjNull(this._view)) {
1854		this._swap(this._rows, from, to);
1855	} else {
1856		this._swap(this._view, from, to);
1857		this._swap(this._rows, this.getRowIndex(this.getRowRefInView(from)),
1858				this.getRowIndex(this.getRowRefInView(to)));
1859	}
1860	this.fireRowSwapped(from, to);
1861	this.setPosition(to, true);
1862};
1863
1864/**
1865 * rowIdx와 근접한 행번호를 구한다.( rowIdx가 0보다 작으면 0을 행의 갯수보다 크거나 같으면 행의 갯수 - 1을 리턴한다. )
1866 *
1867 * @param rowIdx 행위치
1868 * @returns Number 행 인덱스
1869 * @author 김흥수
1870 * @since 2015-08-25
1871 * @version 1.0
1872 */
1873DataSet.prototype.getNearIndex = function(rowIdx) {
1874	if (rowIdx < 0)
1875		return 0;
1876	if (rowIdx >= this.size())
1877		return this.size() - 1;
1878	return rowIdx;
1879};
1880
1881/**
1882 * 특정 Row의 위치를 이동시킴.
1883 *
1884 * @param arr 배열
1885 * @param from 이동할 행 인덱스
1886 * @param to 이동해서 옮겨 갈 곳의 행 인덱스
1887 * @author Jun.
1888 * @since 2013-03-28
1889 * @version 1.0
1890 */
1891DataSet.prototype._swap = function(arr, from, to) {
1892	var temp = arr[from];
1893	arr[from] = arr[to];
1894	arr[to] = temp;
1895};
1896
1897/**
1898 * 특정 Row의 Column의 데이터를 출력함
1899 *
1900 * @param index 행 인데스
1901 * @param key 컬럼명
1902 * @returns json 객체 또는 컬럼 값
1903 * @author Jun.
1904 * @since 2013-03-28
1905 * @version 1.0
1906 */
1907DataSet.prototype.get = function(index, key) {
1908
1909	if (typeof (index) == "undefined" || index < 0 || index >= this.size())
1910		throw "잘못된 Index입니다.";
1911
1912	if (typeof (key) == "undefined")
1913		return this.getRowRefInView(index).get();
1914	if (!this._columns.hasColumn(key)) { // 컬럼이 정의되지 않았거나 컬럼에 해당 키가 존재하지 않을경우
1915		//console.log('get key->'+key)
1916		throw "존재하지 않은 컬럽입니다.";
1917	}
1918
1919
1920
1921	return this.getRowRefInView(index).get(key);
1922};
1923/**
1924 * 특정 Row의 Column의 데이터를 출력함
1925 *
1926 * @param index 행 인데스
1927 * @param key 컬럼명
1928 * @returns json 객체 또는 컬럼 값
1929 * @author Jun.
1930 * @since 2013-03-28
1931 * @version 1.0
1932 */
1933DataSet.prototype.getInRows = function(index, key) {
1934
1935	if (typeof (index) == "undefined" || index < 0 || index >= this.rowSize())
1936		throw "잘못된 Index입니다.";
1937
1938	if (typeof (key) == "undefined")
1939		return this.getRowRef(index).get();
1940
1941	if (!this._columns.hasColumn(key)) { // 컬럼이 정의되지 않았거나 컬럼에 해당 키가 존재하지 않을경우
1942		console.log('getInRows key-'+key)
1943		throw "존재하지 않은 컬럽입니다.";
1944	}
1945
1946	return this.getRowRef(index).get(key);
1947};
1948
1949/**
1950 * 특정 Row의 행 상태를 구함
1951 *
1952 * @param index 행인덱스
1953 * @returns string 행의 변경 상태 ("INSERT","UPDATE","NORMAL")
1954 * @author Jun.
1955 * @since 2013-03-28
1956 * @version 1.0
1957 */
1958DataSet.prototype.getStatus = function(index) {
1959	if (typeof (index) == "undefined" || index < 0 || index >= this.size())
1960		throw "잘못된 Index입니다.";
1961
1962	return this.getRowRefInView(index).getStatus();
1963};
1964
1965
1966/**
1967 * 특정 Row의 행 상태를 설정함
1968 *
1969 * @param index 행인덱스
1970 * @param status 상태값
1971 * @returns string 행의 변경 상태 ("INSERT","UPDATE","NORMAL")
1972 * @author Jun.
1973 * @since 2013-03-28
1974 * @version 1.0
1975 */
1976
1977/**
1978 *
1979 */
1980DataSet.prototype.setStatus = function(index, status) {
1981
1982	if (typeof (index) == "undefined" || index < 0 || index >= this.size())
1983		throw "잘못된 Index입니다.";
1984
1985	if (typeof (status) == "undefined" || !(status == DataSet.DataSetStatus.INSERT
1986			                               || status == DataSet.DataSetStatus.UPDATE
1987			                               || status == DataSet.DataSetStatus.DELETE
1988			                               || status == DataSet.DataSetStatus.NORMAL )
1989	    )
1990		throw "잘못된 status입니다.";
1991
1992	return this.getRowRefInView(index).setStatus(status);
1993};
1994
1995/**
1996 * 데이타셑의 수정여부를 구함
1997 *
1998 * @returns boolean 변경 상태이면 true
1999 * @author Jun.
2000 * @since 2013-03-28
2001 * @version 1.0
2002 */
2003DataSet.prototype.isUpdate = function() {
2004	return this._deletedRows.length > 0 || this._rows.any(function(v) {
2005		return v.getStatus() != DataSet.DataSetStatus.NORMAL;
2006	});
2007};
2008
2009/**
2010 * 특정 행의 cloned dataSetRow를 리턴함
2011 *
2012 * @param index 행 인덱스
2013 * @returns Object 행 데이타
2014 * @author Jun.
2015 * @since 2013-03-28
2016 * @version 1.0
2017 */
2018DataSet.prototype.clone = function(index) {
2019	if (typeof (index) == "undefined" || index < 0 || index >= this.size())
2020		throw "잘못된 Index입니다.";
2021
2022	if (typeof (key) == "undefined")
2023		return this.getRowRefInView(index).clone();
2024	return null;
2025};
2026
2027/**
2028 * 특정 Row의 Column의 오리지널 데이터를 출력함(오리지널 데이타란 변경되기 전 상태의 데이타를 말한다.)
2029 *
2030 * @param index 행인덱스
2031 * @param key 컬럼명
2032 * @returns Object 데이타 객체
2033 * @author Jun.
2034 * @since 2013-03-28
2035 * @version 1.0
2036 */
2037DataSet.prototype.getOrg = function(index, key) {
2038	if (typeof (key) == "undefined")
2039		return this.getRowRefInView(index).getOrg();
2040
2041	if (!this._columns.hasColumn(key)) { // 컬럼이 정의되지 않았거나 컬럼에 해당 키가 존재하지 않을경우
2042		console.log('getOrg key-'+key)
2043		throw "존재하지 않은 컬럽입니다.";
2044	}
2045
2046	return this.getRowRefInView(index).getOrg(key);
2047};
2048;
2049
2050/**
2051 * 생존해 있는 모든 데이터를 복사하여 출력함.
2052 *
2053 * @returns rows 객체 배열
2054 * @author Jun.
2055 * @since 2013-03-28
2056 * @version 1.0
2057 */
2058DataSet.prototype.getAll = function() {
2059	return this.mapInRows(function(dataSetRow) {
2060		return DataSet.Util.objectClone(dataSetRow.get());
2061	});
2062};
2063
2064/**
2065 * 필터링된 모든 데이터를 복사하여 출력함.
2066 *
2067 * @returns rows 객체 배열
2068 * @author Jun.
2069 * @since 2013-03-28
2070 * @version 1.0
2071 */
2072DataSet.prototype.getViewAll = function() {
2073	return this.mapInView(function(dataSetRow) {
2074		return DataSet.Util.objectClone(dataSetRow.get());
2075	});
2076};
2077
2078/**
2079 * 모든 오리지널 데이터를 복사하여 출력함.
2080 *
2081 * @returns rows 객체 배열
2082 * @author Jun.
2083 * @since 2013-03-28
2084 * @version 1.0
2085 */
2086DataSet.prototype.getOrgAll = function() {
2087	return this.mapIfInRows(function(dataSetRow) {
2088		return DataSet.Util.objectClone(dataSetRow.getOrg());
2089	}, function(dataSetRow) {
2090		return dataSetRow.getStatus() != DataSet.DataSetStatus.INSERT;
2091	}).concat(this.mapInDeleted(function(dataSetRow) {
2092		return DataSet.Util.objectClone(dataSetRow.getOrg());
2093	}));
2094};
2095
2096/**
2097 * 서버에 전송할때 사용할 데이터를 출력함 - type이 없을 경우 생존해 있는 모든 데이터를 NORMAL로 출력함. - type이 "U"인
2098 * 경우 현재 데이터 상태를 출력함.
2099 *
2100 * @param type 추출할 행의 종류 "N" : Normal , "U" : Updated , "A" : All
2101 * @returns rows 객체 배열( 서버 전송용으로 행 상태를 컬럼에 포함함.)
2102 * @author Jun.
2103 * @since 2013-03-28
2104 * @version 1.0
2105 */
2106DataSet.prototype.getAllData = function(type,dataSetName) {
2107	type = gf_Default(type, "N");
2108
2109	var fDel = function(dataSetRow, rowIndex) {
2110		var row = DataSet.Util.objectClone(dataSetRow.getOrg());
2111		row[DataSet.StatusColumn] = DataSet.DataSetStatus.DELETE;
2112		row[DataSet.RowNoColumn] = -rowIndex;
2113		if(! gf_IsNull(dataSetName)) row[DataSet.DataSetNameColumn] = dataSetName;
2114		return row;
2115	};
2116	var fRows = function(dataSetRow, rowIndex) {
2117		var row = DataSet.Util.objectClone(dataSetRow.getCurrentData());
2118		row[DataSet.StatusColumn] = dataSetRow.getStatus();
2119		if (row[DataSet.StatusColumn] == DataSet.DataSetStatus.UPDATE)
2120			row[DataSet.OrgRowColumn] = DataSet.Util.objectClone(dataSetRow
2121					.getOrg());
2122		row[DataSet.RowNoColumn] = rowIndex;
2123		if(! gf_IsNull(dataSetName)) row[DataSet.DataSetNameColumn] = dataSetName;
2124		return row;
2125	};
2126
2127	if (type == "N") {
2128		return this.mapInView(function(dataSetRow, rowIndex) {
2129			var row = DataSet.Util.objectClone(dataSetRow.getCurrentData());
2130			row[DataSet.StatusColumn] = DataSet.DataSetStatus.NORMAL;
2131			row[DataSet.RowNoColumn] = rowIndex;
2132			if(! gf_IsNull(dataSetName)) row[DataSet.DataSetNameColumn] = dataSetName;
2133			return row;
2134		});
2135	} else if (type.toUpperCase() == "U") {
2136		return this.mapInDeleted(fDel).concat(
2137				this.mapIfInRows(fRows, function(dataSetRow, rowIndex) {
2138					return !dataSetRow.isNormal();
2139				}));
2140	} else if (type.toUpperCase() == "A") {
2141		return this.mapInDeleted(fDel).concat(this.mapInRows(fRows));
2142	}
2143	return [];
2144};
2145
2146DataSet.prototype.saveAs = function(fileType, fileName, dataType) {
2147	var rows = this.getAll();
2148	fileName = gf_IsObjNull(fileName) ? "noname" : fileName;
2149	var cols = this._columns.getColumns();
2150
2151	if (cols == null) {
2152		var i = 0;
2153		var firstData = this.getRowRef(0).get();
2154		cols = new Array();
2155		for ( var key in firstData) {
2156			cols[i++] = key;
2157		}
2158	}
2159
2160	if (typeof (fileType) == "undefined" || fileType == "excel") {
2161		var str = '';
2162		var line = '';
2163
2164		for (var index = 0; index < cols.length; index++) {
2165			var col = cols[index];
2166
2167			col = typeof (col) == "undefined" ? "" : col;
2168			col = col.indexOf(",") > 0 ? "\"" + col + "\"" : col;
2169
2170			if (index > 0)
2171				line += ',';
2172
2173			line += col;
2174		}
2175
2176		str += line + '\r\n';
2177
2178		for (var i = 0; i < rows.length; i++) {
2179			line = '';
2180			for (var index = 0; index < cols.length; index++) {
2181				var col = cols[index];
2182				var val = rows[i][col];
2183
2184				val = typeof (val) == "undefined" ? "" : val;
2185				if (typeof (val) == "string")
2186					val = val.indexOf(",") > 0 ? "\"" + val + "\"" : val;
2187
2188				if (index > 0)
2189					line += ',';
2190
2191				line += val;
2192			}
2193
2194			str += line + '\r\n';
2195		}
2196
2197		saveAsCSV(str, fileName);
2198	}
2199};
2200
2201/**
2202 * 데이터를 처음 상태로 되돌림. -- 주의사항 : 데이터의 처음 위치를 보장하진 않음. -- 향후 상황에 따라 Array를 이용하여
2203 * 위치정보를 담아두는 로직으로 변경하여 위치보장 가능함.
2204 *
2205 * @author Jun.
2206 * @since 2013-03-28
2207 * @version 1.0
2208 */
2209DataSet.prototype.reset = function() {
2210	if (this._deletedRows.length > 0) {
2211		this._rows = this._rows.concat(this._deletedRows);
2212		this._deletedRows = [];
2213	}
2214
2215	for (var i = this.rowSize() - 1; i >= 0; i--) {
2216		if (this.getRowRef(i).getStatus() == DataSet.DataSetStatus.INSERT) {
2217			this._rows.remove(i);
2218		} else if (this.getRowRef(i).getStatus() == DataSet.DataSetStatus.UPDATE) {
2219			this.getRowRef(i).reset();
2220		}
2221	}
2222	this._filtering(true);
2223	this.setPosition(-1, true);
2224};
2225
2226/**
2227 * Filtering 될 callBack 함수를 지정함.
2228 * <pre>
2229 * filter로 사용될 수 있는 것은 문자열 또는 함수이다.
2230 * 함수의 경우에는 그 스펙이 function(dataSetRow) { return boolean ; } 형식이어야 한다.
2231 * 어기서 dataSetRow는 해당 데이타셑의 DataSetRow 형 객체이다.
2232 * 문자열로 필터를 정하는 경우 문자열은 일반 자바스크립트 boolean 식으로 평가될 수 있는 식으로 이루어져야 한다.
2233 * 또한 필터 식 안에서는 해당 데이타셑에 있는 컬럼을 컬럼 이름으로 접근 가능하다.
2234 * 예를 들어 refCd1 이라는 컬럼이 있다면 다음과 같은 필터식은 유효하다.
2235 * " refCd1 == 'A' || gf_IsNull(refCd1) "
2236 * </pre>
2237 * @param filter 데이타셑에 적용할 필터이다. 필터는 callback 함수가 될 수도 있고 필터링 산식으로 이루어진 문자열일 수도 있다.
2238 * @author Jun.
2239 * @since 2013-03-28
2240 * @version 1.0
2241 */
2242DataSet.prototype.filter = function(filter) {
2243	this._filter = (typeof (filter) == "undefined") ? null : filter;
2244	this._filtering();
2245	this.setPosition(-1, true);
2246};
2247
2248/**
2249 * CallBack 함수에 의해 데이터가 Filtering 됨.
2250 * 내부함수
2251 *
2252 * @author Jun.
2253 * @since 2013-03-28
2254 * @version 1.0
2255 */
2256DataSet.prototype._filtering = function(isLoad) {
2257	isLoad = typeof (isLoad) == "undefined" ? false : isLoad;
2258
2259	this._view = null;
2260	if (!gf_IsObjNull(this._filter)) {
2261		if(typeof(this._filter) == "string") {
2262			var filterFunc =this._stringFiltering(this._filter);
2263			try {
2264				this._view = this._rows.filter(filterFunc);
2265			} catch (ex) {
2266				this.filter(null);
2267				throw ex;
2268			}
2269
2270		} else {
2271			this._view = this._rows.filter(this._filter);
2272		}
2273	}
2274	this._binder.draw(isLoad);
2275};
2276/*
2277 * 내부함수
2278 */
2279DataSet.prototype._stringFiltering = function(filter) {
2280
2281	//var prev = (this._columns.getColumns().hvcMap(function(colName){ return "var "+colName+" = dataSetRow.get('"+colName+"'); "  ; })).join(" ");
2282	var prev = (Array.prototype.hvcMap.call(this._columns.getColumns(),function(colName){ return "var "+colName+" = dataSetRow.get('"+colName+"'); "  ; })).join(" ");
2283	var filterStr = prev + "return (" + filter + ");" ;
2284
2285
2286	return new Function("dataSetRow",filterStr );
2287};
2288
2289/**
2290 * 바인딩 혹은 필터에 의해 보여질 가상 데이터 Row 출력함. -- 주의사항 : 실제 데이터셑의 데이터Row가 Call By
2291 * Reference --
2292 *
2293 * @returns Array 화면에 보이는 행들의 배열
2294 * @author Jun.
2295 * @since 2013-03-28
2296 * @version 1.0
2297 */
2298DataSet.prototype.view = function() {
2299	return gf_IsObjNull(this._view) ? this._rows : this._view;
2300};
2301
2302/**
2303 * 바이딩 혹은 필터에 의해 보여질 가상 데이터 Row 출력함. -- 주의사항 : 실제 데이터셑의 데이터Row가 Call By
2304 * Reference --
2305 *
2306 * @returns Array 삭제된 행들의 배열
2307 * @author 김흥수
2308 * @since 2015-09-22
2309 * @version 1.0
2310 */
2311DataSet.prototype.deletedRows = function() {
2312	return this._deletedRows;
2313};
2314
2315/**
2316 * 바이딩 혹은 필터에 의해 보여질 가상 데이터 Row 행 수를출력함.
2317 *
2318 * @returns size
2319 * @author Jun.
2320 * @since 2013-03-28
2321 * @version 1.0
2322 */
2323DataSet.prototype.size = function() {
2324	return this._view == null ? this.rowSize() : this._view.length;
2325};
2326
2327/**
2328 * 필터되지 않은 데이타 행의 수를 리턴함
2329 *
2330 * @returns 필터링과 무관하게 전체 행의 갯수를 리턴함
2331 * @author Jun.
2332 * @since 2013-03-28
2333 * @version 1.0
2334 */
2335DataSet.prototype.rowSize = function() {
2336	return this._rows.length;
2337};
2338
2339/**
2340 * 현재 데이터 상태를 오리지널 데이터로 변경.
2341 * 저장 후 행 상태를 normal로 바꾸기 위해 사용한다.
2342 *
2343 * @author Jun.
2344 * @since 2013-03-28
2345 * @version 1.0
2346 */
2347DataSet.prototype.apply = function(isPosition) {
2348	this._deletedRows = [];
2349
2350	isPosition = typeof (isPosition) == "undefined" ? true : false;
2351
2352	this.forEachInRows(function(dataSetRow) {
2353		dataSetRow.apply();
2354	});
2355	if(isPosition) {
2356		this._filtering();
2357		this.setPosition(-1, true);
2358	}
2359};
2360
2361/**
2362 * 검색할 컬럼의 값이 일치하는 Index. -- 조회된 데이터가 없을시 -1을 출력함.
2363 *
2364 * @param colNmOrFunction (string,function)
2365 *            function인 경우는 callback 함수이어야 하며 function(현재값,인덱스,배열)의 스펙을 가지고 리턴값은
2366 *            boolean이어야 한다.
2367 * @param startIndex 시작행 인덱스
2368 * @param value 찾고자하는 값
2369 * @returns index 발견한 행 인덱스
2370 * @author Jun.
2371 * @since 2013-03-28
2372 * @version 1.0
2373 */
2374DataSet.prototype.findNext = function(colNmOrFunction, startIndex, value) {
2375	if (typeof colNmOrFunction === 'function') {
2376		//return this.view().findNextIndex(colNmOrFunction, startIndex);
2377		return Array.prototype.findNextIndex.call(this.view(),colNmOrFunction, startIndex);
2378	} else {
2379		//return this.view().findNextIndex(function(v) {
2380		return Array.prototype.findNextIndex.call(this.view(),function(v) {
2381			return v.get(colNmOrFunction) == value;
2382		}, startIndex);
2383	}
2384};
2385/**
2386 * 검색할 컬럼의 값이 일치하는 Index. -- 조회된 데이터가 없을시 -1을 출력함.
2387 *
2388 * @param colNmOrFunction (string,function)
2389 *            function인 경우는 callback 함수이어야 하며 function(현재값,인덱스,배열)의 스펙을 가지고 리턴값은
2390 *            boolean이어야 한다.
2391 * @param startIndex 시작행 인덱스
2392 * @param value 찾고자하는 값
2393 * @returns index 발견한 행 인덱스
2394 * @author Jun.
2395 * @since 2013-03-28
2396 * @version 1.0
2397 */
2398DataSet.prototype.findInRowsNext = function(colNmOrFunction, startIndex, value) {
2399	if (typeof colNmOrFunction === 'function') {
2400		//return this.view().findNextIndex(colNmOrFunction, startIndex);
2401		return Array.prototype.findNextIndex.call(this._rows,colNmOrFunction, startIndex);
2402	} else {
2403		//return this.view().findNextIndex(function(v) {
2404		return Array.prototype.findNextIndex.call(this._rows,function(v) {
2405			return v.get(colNmOrFunction) == value;
2406		}, startIndex);
2407	}
2408};
2409
2410/**
2411 * 검색할 컬럼의 값이 일치하는 Index. -- 조회된 데이터가 없을시 -1을 출력함.
2412 *
2413 * @param colNmOrFunction(string,function)
2414 *            function인 경우는 callback 함수이어야 하며 function(현재값,인덱스,배열)의 스펙을 가지고 리턴값은
2415 *            boolean이어야 한다.
2416 * @param value 찾고자 하는 값
2417 * @returns index 행 인덱스
2418 * @author Jun.
2419 * @since 2013-03-28
2420 * @version 1.0
2421 */
2422DataSet.prototype.find = function(colNmOrFunction, value) {
2423	return this.findNext(colNmOrFunction, 0, value);
2424};
2425/**
2426 * 검색할 컬럼의 값이 일치하는 Index. -- 조회된 데이터가 없을시 -1을 출력함.
2427 *
2428 * @param colNmOrFunction(string,function)
2429 *            function인 경우는 callback 함수이어야 하며 function(현재값,인덱스,배열)의 스펙을 가지고 리턴값은
2430 *            boolean이어야 한다.
2431 * @param value 찾고자 하는 값
2432 * @returns index 행 인덱스
2433 * @author Jun.
2434 * @since 2013-03-28
2435 * @version 1.0
2436 */
2437DataSet.prototype.findInRows = function(colNmOrFunction, value) {
2438	return this.findInRowsNext(colNmOrFunction, 0, value);
2439};
2440
2441/**
2442 * 검색할 컬럼의 값이 일치하는 Row의 DataSetRow를 출력함. -- 조회된 데이터가 없을시 'undefined'을 출력함.
2443 *
2444 * @param colNmOrFunction(string,function)
2445 *            function인 경우는 callback 함수이어야 하며 function(현재값,인덱스,배열)의 스펙을 가지고 리턴값은
2446 *            boolean이어야 한다.
2447 * @param startIndex 검색을 시작할 행의 인덱스
2448 *            시작행 인덱스
2449 * @param value 찾고자 하는 값
2450 * @returns Object row(Dataset.DataSetRow) 발견된 행의 DataSetRow
2451 * @author Jun.
2452 * @since 2013-03-28
2453 * @version 1.0
2454 */
2455DataSet.prototype.findNextRow = function(colNmOrFunction, startIndex, value) {
2456	if (typeof colNmOrFunction === 'function') {
2457		//return this.view().findNext(colNmOrFunction, startIndex);
2458		return Array.prototype.findNext.call(this.view(),colNmOrFunction, startIndex);
2459	} else {
2460		//return this.view().findNext(function(v) {
2461		return Array.prototype.findNext.call(this.view(),function(v) {
2462			return v.get(colNmOrFunction) == value;
2463		}, startIndex);
2464	}
2465};
2466
2467/**
2468 * 검색할 컬럼의 값이 일치하는 Row의 DataSetRow를 출력함. -- 조회된 데이터가 없을시 'undefined'을 출력함.
2469 *
2470 * @param colNmOrFunction(string,function)
2471 *            function인 경우는 callback 함수이어야 하며 function(현재값,인덱스,배열)의 스펙을 가지고 리턴값은
2472 *            boolean이어야 한다.
2473 * @param value 찾고자하는 값
2474 * @returns row(Dataset.DataSetRow) 발견된 행의 DataSetRow
2475 * @author Jun.
2476 * @since 2013-03-28
2477 * @version 1.0
2478 */
2479DataSet.prototype.findRow = function(colNmOrFunction, value) {
2480	return this.findNextRow(colNmOrFunction, 0, value);
2481};
2482
2483/**
2484 * 검색할 컬럼의 값이 일치하는 Index. -- 조회된 데이터가 없을시 -1을 출력함.
2485 *
2486 * @param dataSetRow
2487 * @returns index(int)
2488 * @author Jun.
2489 * @since 2013-03-28
2490 * @version 1.0
2491 */
2492DataSet.prototype.dataSetRowTofind = function(dataSetRow) {
2493	return this.getRowIndexInView(dataSetRow);
2494};
2495
2496
2497/**
2498 * 데이터셑에 컬럼명 목록가져온다
2499 *
2500 * @returns 컬럼명 배열
2501 * @author Jun.
2502 * @since 2013-03-28
2503 * @version 1.0
2504 */
2505DataSet.prototype.getColumns = function() {
2506	return this._columns.getColumns();
2507};
2508
2509/**
2510 * 데이터셑에 컬럼정보 목록 정보를 가져온다.
2511 *
2512 * @returns DataSet.DataSetColumns
2513 * @author Jun.
2514 * @since 2013-03-28
2515 * @version 1.0
2516 */
2517DataSet.prototype.getColumnInfos = function() {
2518	return this._columns;
2519};
2520/**
2521 * 데이터셑에 컬럼 정보 목록을 설정한다.
2522 * @param columns <pre>컬럼 목록
2523 *        columns의 종류는 총 4가지가 가능하다.
2524 *        1) 컬럼명의 문자열 배열
2525 *           ex) ["column1","column2","column3"]
2526 *        2) DataSet.DataSetColumn 의 배열
2527 *           ex) [ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]
2528 *        3) json 객체 배열 (객체의 가능한 속성은 columnId , dataType , columnTitle , fmt , isVirtual , maxLength , dispFmt 이다 )
2529 *           ex) [ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ]
2530 *        4) json 객체 ( 필드명을 키로 하고 컬럼 정보를 속성으로 하는 json 객체이다. 컬럼 정보의 속성은 fieldType , fieldTitle , fieldFormat , virtualField , fieldLength , fieldDisplayFormat 이 가능하다. )
2531 *           ex) { "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" } , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }
2532 * </pre>
2533 * @author Jun.
2534 * @since 2013-03-28
2535 * @version 1.0
2536 */
2537DataSet.prototype.setColumns = function(columns) {
2538	this._columns = new DataSet.DataSetColumns(columns);
2539};
2540
2541/**
2542 * 데이타셋 컬럼의 갯수
2543 *
2544 * @returns 컬럼 갯수
2545 * @author 김흥수
2546 * @since 2015-09-04
2547 * @version 1.0
2548 */
2549DataSet.prototype.fieldCount = function() {
2550	if (gf_IsObjNull(this._columns))
2551		return 0;
2552	return this._columns.size();
2553};
2554
2555/**
2556 * 특정 컬럼 인덱스의 컬럼명을 구한다.
2557 *
2558 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2559 * @returns 컬럼명 만약 지정하지 않을 경우는 읽기 함수로 동작하고 지정하면 설정 힘수로 동작한다.
2560 * @author 김흥수
2561 * @since 2015-09-04
2562 * @version 1.2
2563 */
2564DataSet.prototype.fieldName = function(id) {
2565	if (gf_IsObjNull(this._columns))
2566		return null;
2567	return this._columns.fieldName(id);
2568};
2569
2570/**
2571 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 타입을 구하거나 설정한다.
2572 *
2573 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2574 * @param v 컬럼 데이타 타입 . 데이타 타입은 DataSet.DataType에 정의되어 있다. - 만약 지정하지 않을 경우는 읽기 함수ë¡
2574œ 동작하고 지정하면 설정 힘수로 동작한다.
2575 * @returns 컬럼 데이타 타입
2576 * @author 김흥수
2577 * @since 2015-09-04
2578 * @version 1.2
2579 */
2580DataSet.prototype.fieldType = function(id, v) {
2581	if (gf_IsObjNull(this._columns))
2582		return null;
2583	return this._columns.fieldType(id, v);
2584};
2585
2586/**
2587 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 길이를 구하거나 설정한다.
2588 *
2589 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2590 * @param v 컬럼 데이타 길이 - 만약 지정하지 않을 경우는 읽기 함수로 동작하고 지정하면 설정 힘수로 동작한다.
2591 * @returns 컬럼 데이타 길이
2592 * @author 김흥수
2593 * @since 2015-10-15
2594 * @version 1.2
2595 */
2596DataSet.prototype.fieldLength = function(id, v) {
2597	if (gf_IsObjNull(this._columns))
2598		return null;
2599	return this._columns.fieldLength(id, v);
2600};
2601
2602/**
2603 * 특정 컬럼 인덱스(또는 컬럼명)의 가상 여부를 구하거나 설정한다.
2604 *
2605 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2606 * @param v boolean 값으로 가상 컬럼 여부를 지정한다. 가상 컬럼의 경우 해당 컬럼이 수정되어도 행의 행의 상태는 변경되지 않는다.  - 만약 지정하지 않을 경우는 읽기 함수로 동작하고 지정하면 설정 힘수로 동작한다.
2607 * @returns 컬럼의 가상 여부
2608 * @author 김흥수
2609 * @since 2015-09-04
2610 * @version 1.2
2611 */
2612DataSet.prototype.virtualField = function(id, v) {
2613	if (gf_IsObjNull(this._columns))
2614		return null;
2615	return this._columns.virtualField(id, v);
2616};
2617
2618/**
2619 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 타이틀을 구하거나 설정한다.
2620 *
2621 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2622 * @param v 컬럼 타이틀  - 만약 지정하지 않을 경우는 읽기 함수로 동작하고 지정하면 설정 힘수로 동작한다.
2623 * @returns 컬럼 타이틀
2624 * @author 김흥수
2625 * @since 2015-09-04
2626 * @version 1.2
2627 */
2628DataSet.prototype.fieldTitle = function(id, v) {
2629	if (gf_IsObjNull(this._columns))
2630		return null;
2631	return this._columns.fieldTitle(id, v);
2632};
2633
2634/**
2635 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 형식을 구하거나 설정한다.
2636 *
2637 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2638 * @param v 컬럼 데이타 형식  - 만약 지정하지 않을 경우는 읽기 함수로 동작하고 지정하면 설정 힘수로 동작한다.
2639 * @returns 컬럼 데이타 형식
2640 * @author 김흥수
2641 * @since 2015-09-04
2642 * @version 1.2
2643 */
2644DataSet.prototype.fieldFormat = function(id, v) {
2645	if (gf_IsObjNull(this._columns))
2646		return null;
2647	return this._columns.fieldFormat(id, v);
2648};
2649
2650/**
2651 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 표시 형식을 구하거나 설정한다.
2652 *
2653 * @param id number 또는 string 으로 컬럼의 인덱스또는 컬럼 명을 지정한다. 인덱스의 경우는 0 base 임
2654 * @param v string 컬럼의 표시 형식 - 만약 지정하지 않을 경우는 읽기 함수로 동작하고 지정하면 설정 힘수로 동작한다.
2655 * @returns 컬럼 데이타 표시 형식
2656 * @author 김흥수
2657 * @since 2015-09-04
2658 * @version 1.2
2659 */
2660DataSet.prototype.fieldDisplayFormat = function(id, v) {
2661	if (gf_IsObjNull(this._columns))
2662		return null;
2663	return this._columns.fieldDisplayFormat(id, v);
2664};
2665
2666/**
2667 * 데이터셑에 객체를 바인딩함
2668 *
2669 * @param obj 바인딩할객체
2670 * @param option 옵션
2671 * @author Jun.
2672 * @since 2013-03-28
2673 * @version 1.0
2674 */
2675DataSet.prototype.bind = function(obj, option) {
2676	var gridObj = $(obj).data("grid_instance");
2677	if (!gf_IsObjNull(gridObj)) {
2678		this._binder.add(gridObj, option);
2679	} else {
2680		this._binder.add(obj, option);
2681	}
2682};
2683/**
2684 * 데이터셑에 HTML Element를 바인드 해제시킴
2685 *
2686 * @param obj 객체
2687 * @author Jun.
2688 * @since 2013-03-28
2689 * @version 1.0
2690 */
2691DataSet.prototype.unBind = function(obj) {
2692	var gridObj = $(obj).data("grid_instance");
2693	if (!gf_IsObjNull(gridObj)) {
2694		this._binder.remove(gridObj);
2695	} else {
2696		this._binder.remove(obj);
2697	}
2698};
2699
2700/**
2701 * Dataset의 데이터로 조회용 테이블을 그린다. 이것은 대명 법인사 ASP용으로 추가 된것으로 다른데서는 사용
2702 * 하려면 수정을거쳐야 한다
2703 *
2704 * @param 그릴 테이블 개체 id
2705 * @param 테이블 컬럼 정보
2706 * @author hunter byun
2707 * @since 2018-08-13
2708 * @version 1.0
2709 */
2710DataSet.prototype.viewTable = function(tableId, colInfos, tableClass) {
2711	var tbClass = gf_Default(tableClass, "table02");
2712	var buttonClass = "";
2713	if ( tbClass == "table02") {
2714		buttonClass = "button_bsm bsm_bd";
2715	}
2716	else {
2717		buttonClass = "button button_grey";
2718	}
2719
2720	var tableObj = $("#"+tableId);
2721
2722	tableObj.empty();
2723
2724
2725	var that = this;
2726	tableObj.attr("border", "0");
2727	tableObj.attr("cellspacing", "0");
2728	tableObj.attr("cellpadding", "0");
2729	tableObj.attr("class", tbClass);
2730
2731	var tbody = $("<tbody></tbody>").appendTo(tableObj);
2732	var headerTr = $("<tr></tr>").appendTo(tbody)
2733	// making header
2734	colInfos.forEach ( function (colinfo ) {
2735		var headerCss = "";
2736		if ( !gf_IsNull(colinfo.headerCss) ) {
2737			headerCss = " class='"+colinfo.headerCss+"'";
2738		}
2739		headerTr.append("<th "+headerCss+">"+colinfo.title+"</th>")
2740	});
2741
2742	// makingData
2743	for ( var i = 0; i < that.size() ; i++ ) {
2744		var dataTr = $("<tr></tr>").appendTo(tbody)
2745		// making header
2746
2747		colInfos.forEach ( function (colinfo ) {
2748			//that.getRowRefInView(i).get(colinfo.name);
2749			var dataCss = "";
2750			if ( !gf_IsNull(colinfo.dataCss) ) {
2751				dataCss = " class='"+colinfo.dataCss+"' ";
2752			}
2753			var styleStr = " style='";
2754			if ( !gf_IsNull(colinfo.width) ) {
2755				styleStr = styleStr+"width:"+colinfo.width+"px;";
2756			}
2757
2758			if ( !gf_IsNull(colinfo.align) ) {
2759				styleStr = styleStr+"text-align:"+colinfo.align+";";
2760			}
2761
2762			if ( colinfo.coltype == "textarea") {
2763				styleStr = styleStr + "white-space:pre-wrap;";
2764			}
2765
2766			styleStr = styleStr+"'";
2767
2768
2769			if ( colinfo.coltype == 'checkbox') {
2770				var val = '';
2771				try {
2772					val = that.get(i, colinfo.name);
2773				}
2774				catch (e) {
2775				    val = i;
2776				}
2777				dataTr.append('<td '+dataCss+styleStr+'><input type="checkbox" value="'+val+'" name="'+colinfo.name+'" id="'+colinfo.name+i+'" ><label for="'+colinfo.name+i+'"><div></div></label></td>');
2778			}
2779			else if (colinfo.coltype == "button") {
2780				var buttonTd = $("<td "+dataCss+styleStr+"></td>").appendTo(dataTr);
2781
2782				var thisId = tableObj[0].id +"_button_"+colinfo.name;
2783			    var callBackName = thisId+"_callback";
2784				window[callBackName] = function(row,cell) {
2785			        if(! gf_IsObjNull(colinfo.callback)) {
2786			        	colinfo.callback.call(null,row,cell);
2787			        }
2788			    };
2789
2790				var button = $('<button onclick="'+callBackName+'('+i+',\''+colinfo.name+'\')" name="'+colinfo.name+'" id="'+colinfo.name+i+'" class="'+buttonClass+'" alt="'+colinfo.buttontext+'" title="'+colinfo.buttontext+'"> '+colinfo.buttontext+' </button>').appendTo(buttonTd);
2791
2792			}
2793			else if ( colinfo.coltype == "link" ) {
2794				var linkTd = $("<td "+dataCss+styleStr+"></td>").appendTo(dataTr);
2795				var val = that.get(i, colinfo.name);
2796				var thisId = tableObj[0].id +"_"+colinfo.name;
2797			    var callBackName = thisId+"_callback";
2798				window[callBackName] = function(row,cell) {
2799			        if(! gf_IsObjNull(colinfo.callback)) {
2800			        	colinfo.callback.call(null,row,cell);
2801			        }
2802			    };
2803
2804				var link = $('<a href="javascript:void(0)" onclick="'+callBackName+'('+i+',\''+colinfo.name+'\')"></a>').appendTo(linkTd);
2805				link.append(val);
2806			}
2807			else if ( colinfo.coltype == "custom") {
2808				var viewVal = colinfo.callback.call(null, i, colinfo.name);
2809
2810				if ( gf_IsObjNull(colinfo.onclickCallback) ) {
2811					var td = $("<td "+dataCss+styleStr+">"+viewVal+"</td>").appendTo(dataTr);
2812				}
2813				else {
2814
2815					var thisId = tableObj[0].id +"_"+colinfo.name;
2816				    var callBackName = thisId+"_clickcallback";
2817					window[callBackName] = function(row,cell) {
2818				        if(! gf_IsObjNull(colinfo.onclickCallback)) {
2819				        	colinfo.onclickCallback.call(null,row,cell);
2820				        }
2821				    };
2822
2823				    var linkTd = $("<td "+dataCss+styleStr+" onclick='"+callBackName+"("+i+",\""+colinfo.name+"\")'>"+viewVal+"</td>").appendTo(dataTr);
2824
2825				    //var link = $('<a href="javascript:void(0)" onclick="'+callBackName+'('+i+',\''+colinfo.name+'\')"></a>
2825').appendTo(linkTd);
2826				    //link.append(viewVal);
2827				    //var td = $("<td "+dataCss+styleStr+"><a href='javascript:void(0)' onclick='"+callBackName+"("+i+",\""+colinfo.name+"\")'>"+viewVal+"</a></td>").appendTo(dataTr);
2828				}
2829			}
2830			else {
2831				var val = that.get(i, colinfo.name);
2832				if ( colinfo.coltype == "number" ) {
2833					var validVal = gf_FormatNumber(gf_UnformatNumber(val),"#,##0")
2834					var td = $("<td "+dataCss+styleStr+">"+validVal+"</td>").appendTo(dataTr);
2835				}
2836				else if ( colinfo.coltype == "date") {
2837					var dateObj = val.toDate(Date.__SAVE_FORMAT__);
2838					var formatVal = dateObj.format(Date.__DISPLAY_FORMAT__);
2839					var td = $("<td "+dataCss+styleStr+">"+formatVal+"</td>").appendTo(dataTr);
2840				}
2841				else {
2842					var td = $("<td "+dataCss+styleStr+">"+val+"</td>").appendTo(dataTr);
2843				}
2844			}
2845		});
2846	}
2847};
2848
2849
2850
2851
2852
2853/**
2854 * 작업중인 데이타 변경을 승인함
2855 *
2856 * @author Jun.
2857 * @since 2013-03-28
2858 * @version 1.0
2859 */
2860DataSet.prototype.saveRow = function() {
2861	this._binder.saveRows();
2862	//if(! gf_IsObjNull(this._children))  this._children.forEachL(function(child){ child.dataSet.saveRow(); });
2863	if(! gf_IsObjNull(this._children))  Array.prototype.forEachL.call(this._children,function(child){ child.dataSet.saveRow(); });
2864};
2865
2866/**
2867 * 서버에 전송할 메타정보를 생성한다.
2868 *
2869 * @param dataSetId 서버에서 사용될 데이타셑의 id
2870 * @returns Object 컬럼 메타 정보
2871 * @author 김흥수
2872 * @since 2015-10-12
2873 * @version 1.2
2874 */
2875DataSet.prototype.makeMetaInfo = function(dataSetId) {
2876	return this._columns.makeMetaInfo(dataSetId);
2877};
2878
2879/**
2880 * 데이타셑의 내용을 문자열로 직렬화한다.
2881 * @returns String 데이타셑 정보에 대한 직렬화된 문자열 표현
2882 * @author 김흥수
2883 * @since 2015-12-01
2884 * @version 1.5
2885 */
2886DataSet.prototype.serialize = function() {
2887	var dataInfo = {};
2888	dataInfo["columns"] = this.getColumnInfos().getColumnInfos();
2889	dataInfo["rows"] = 	this.mapInRows(function(dataSetRow) {
2890		return {"data": dataSetRow.get() , "status" : dataSetRow.getStatus() };
2891	});
2892	dataInfo["deleted"] = 	this.mapInDeleted(function(dataSetRow) {
2893		return dataSetRow.get();
2894	});
2895
2896	return JSON.stringify(dataInfo);
2897};
2898
2899DataSet.prototype.toJsonStr = function () {
2900	var dataInfo = {};
2901	dataInfo["rows"] = 	this.mapInRows(function(dataSetRow) {
2902		return {"data" : dataSetRow.get() };
2903	});
2904
2905	return JSON.stringify(dataInfo);
2906}
2907
2908/**
2909 * 데이타셑의 내용을 문자열로부터 역직렬화한다.
2910 * @author 김흥수
2911 * @since 2015-12-01
2912 * @version 1.5
2913 */
2914DataSet.prototype.deserialize = function(data) {
2915	var _that = this;
2916	var dataInfo = JSON.parse(data);
2917	this.clear();
2918	this.getColumnInfos().setColumns(dataInfo["columns"]);
2919	dataInfo["rows"].forEach(function(row){
2920		var idx = _that.add(row.data);
2921		_that.getRowRef(idx).setStatus(row.status);
2922	});
2923	dataInfo["deleted"].forEach(function(row){
2924		var dataSetRow = new DataSet.DataSetRow(row, _that);
2925		_that._deletedRows.push(dataSetRow);
2926	});
2927	_that._binder.draw();
2928};
2929
2930/**
2931 * @class 데이터셑 Row
2932 * <pre>
2933 * 데이타셑을 생성하는 방법은 세가지 방법이 있다.
2934 * 하나는 new DataSet.DataSetRow(data) : data는 json 객체
2935 * 다른 하나는 new DataSet.DataSetRow(data,dataSet) : data는 json 객체, dataSet은 해당 데이타셑 행이 소속될 데이타셑
2936 * 마지막 하나는 new DataSet.DataSetRow(dataSet) : dataSet은 해당 데이타셑 행이 소속될 데이타셑
2937 * </pre>
2938 * @constructor
2939 * @param obj 데이타셑 행의 데이타
2940 * @param dataSet 이 데이타셑 행이 소속된 데이타 셑
2941 * @author Jun.
2942 * @since 2013-03-28
2943 * @version 1.0
2944 */
2945DataSet.DataSetRow = function(obj, dataSet) { // 데이터 Row
2946	this._data = {};
2947	this._dataSet = null;
2948	this._orgData = null;
2949	this._rowStatus = DataSet.DataSetStatus.NORMAL;
2950
2951	if (typeof (obj) != "undefined") {
2952		if (obj instanceof DataSet) {
2953			this._dataSet = obj;
2954		} else {
2955			this._data = obj;
2956			if (typeof (dataSet) != "undefined")
2957				this._dataSet = dataSet;
2958		}
2959	}
2960};
2961/**
2962 * @class 데이타셑의 validation 정보들
2963 */
2964DataSet.DataSetRow.Validation = {};
2965
2966/**
2967 * 데이타셑 행의 특정 컬럼들이 필수 제약조건을 만족하는지 검사하는 함수이다.
2968 * <pre>
2969 * checkValid 함수에 의해 호출되도록 작성되어 있으며
2970 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
2971 * </pre>
2972 * @param dataSetRow 검사대상 레코드
2973 * @param info validation 검증을 위한 부가정보 { column , title } 객체임.
2974 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
2975 * @author 김흥수
2976 * @since 2015-09-01
2977 * @version 1.0
2978 */
2979DataSet.DataSetRow.Validation.required = function(dataSetRow, info) {
2980	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
2981	var message = gf_Default(info.message, gf_GetMsg("gw.err.required",[ title ]));
2982	if (gf_IsNull(dataSetRow.get(info.column))) {
2983		return {
2984			"column" : info.column,
2985			"message" : message
2986		};
2987	} else {
2988		return null;
2989	}
2990};
2991
2992/**
2993 * 데이타셑 행의 특정 컬럼들이 날짜 형식임을 검증한다.
2994 * <pre>
2995 * checkValid 함수에 의해 호출되도록 작성되어 있으며
2996 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
2997 * </pre>
2998 * @param dataSetRow 상속을 검사대상 레코드
2999 * @param info validation 검증을 위한 부가정보 { column,title,message,dataFormat } 의 객체이다.
3000 *        dataFormat 속성의 기본값은 DataSet.DEFAULT_DATE_FORMAT 이다.
3001 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3002 * @author 김흥수
3003 * @since 2015-09-01
3004 * @version 1.0
3005 */
3006DataSet.DataSetRow.Validation.datechek = function(dataSetRow, info) {
3007	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3008	var message = gf_Default(info.message, gf_GetMsg("gw.err.dataFormat",[ title ]));
3009	var fmt = gf_Default(info.dataFormat, dataSetRow.getDataSet().fieldFormat(info.column));
3010	fmt = gf_Default(fmt,DataSet.DEFAULT_DATE_FORMAT);
3011	if (! gf_IsNull(dataSetRow.get(info.column))) {
3012		var value = dataSetRow.get(info.column);
3013		try {
3014			var dispValue = value.toDate(fmt).format(fmt);
3015			if(dispValue == value) return null;
3016			return {
3017				"column" : info.column,
3018				"message" : message
3019			};
3020		} catch (e) {
3021			return {
3022				"column" : info.column,
3023				"message" : message
3024			};
3025		}
3026
3027	} else {
3028		return null;
3029	}
3030};
3031
3032/**
3033 * 해당 컬럼 자료가 현재 날짜를 초과하지 않는지를 검증한다.
3034 * <pre>
3035 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3036 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3037 * </pre>
3038 * @param dataSetRow 상속을 검사대상 레코드
3039 * @param info validation 검증을 위한 부가정보 { column,title,message,dataFormat } 의 객체이다.
3040 *        dataFormat 속성의 기본값은 DataSet.DEFAULT_DATE_FORMAT 이다.
3041 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3042 * @author 김흥수
3043 * @since 2015-09-01
3044 * @version 1.0
3045 */
3046DataSet.DataSetRow.Validation.maxcurrentdate = function(dataSetRow, info) {
3047	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3048	var message = gf_Default(info.message, gf_GetMsg("gw.err.maxCurrentDate",[ title ]));
3049	var fmt = gf_Default(info.dataFormat, dataSetRow.getDataSet().fieldFormat(info.column));
3050	fmt = gf_Default(fmt,DataSet.DEFAULT_DATE_FORMAT);
3051	if (! gf_IsNull(dataSetRow.get(info.column))) {
3052		var value = dataSetRow.get(info.column);
3053		try {
3054			var dispValue = value.toDate(fmt).format("YYYYMMDD");
3055			var curr = gf_GetServerDate().format("YYYYMMDD");
3056			if(curr < dispValue ) {
3057				return {
3058					"column" : info.column,
3059					"message" : message
3060				};
3061			} else {
3062				return null;
3063			}
3064		} catch (e) {
3065			return {
3066				"column" : info.column,
3067				"message" : message
3068			};
3069		}
3070
3071	} else {
3072		return null;
3073	}
3074};
3075/**
3076 * 해당 컬럼 자료가 현재 년월을 초과하지 않는지를 검증한다.
3077 * <pre>
3078 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3079 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3080 * </pre>
3081 * @param dataSetRow 상속을 검사대상 레코드
3082 * @param info validation 검증을 위한 부가정보 { column,title,message,dataFormat } 의 객체이다.
3083 *        dataFormat 속성의 기본값은 DataSet.DEFAULT_DATE_FORMAT 이다.
3084 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3085 * @author 김흥수
3086 * @since 2015-09-01
3087 * @version 1.0
3088 */
3089DataSet.DataSetRow.Validation.maxcurrentmonth = function(dataSetRow, info) {
3090	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3091	var message = gf_Default(info.message, gf_GetMsg("gw.err.maxCurrentMonth",[ title ]));
3092	var fmt = gf_Default(info.dataFormat, dataSetRow.getDataSet().fieldFormat(info.column));
3093	fmt = gf_Default(fmt,"YYYYMM");
3094	if (! gf_IsNull(dataSetRow.get(info.column))) {
3095		var value = dataSetRow.get(info.column);
3096		try {
3097			var dispValue = value.toDate(fmt).format("YYYYMM");
3098			var curr = gf_GetServerDate().format("YYYYMM");
3099			if(curr < dispValue ) {
3100				return {
3101					"column" : info.column,
3102					"message" : message
3103				};
3104			} else {
3105				return null;
3106			}
3107		} catch (e) {
3108			return {
3109				"column" : info.column,
3110				"message" : message
3111			};
3112		}
3113
3114	} else {
3115		return null;
3116	}
3117};
3118
3119/**
3120 * 데이타셑 행의 특정 컬럼들이 email 형식임을 검증한다.
3121 * <pre>
3122 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3123 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3124 * </pre>
3125 * @param dataSetRow 상속을 검사대상 레코드
3126 * @param info validation 검증을 위한 부가정보 { column,title,message } 의 객체이다.
3127 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3128 * @author 김흥수
3129 * @since 2015-09-01
3130 * @version 1.0
3131 */
3132DataSet.DataSetRow.Validation.email = function(dataSetRow, info) {
3133	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3134	var message = gf_Default(info.message, gf_GetMsg("gw.err.mailAddrFail",[ title ]));
3135	if (! gf_IsNull(dataSetRow.get(info.column))) {
3136		var value = dataSetRow.get(info.column);
3137		if(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value)) {
3138			return null;
3139		} else {
3140			return {
3141				"column" : info.column,
3142				"message" : message
3143			};
3144		}
3145	} else {
3146		return null;
3147	}
3148};
3149
3150/**
3151 * 데이타셑 행의 특정 컬럼들이 password 형식임을 검증한다.
3152 * <pre>
3153 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3154 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3155 * </pre>
3156 * @param dataSetRow 상속을 검사대상 레코드
3157 * @param info validation 검증을 위한 부가정보 { column,message } 의 객체이다.
3158 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3159 * @author 변형구
3160 * @since 2016-01-04
3161 * @version 1.0
3162 */
3163DataSet.DataSetRow.Validation.password = function(dataSetRow, info) {
3164	//var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3165	var message = gf_Default(info.message, gf_GetMsg("gw.err.password"));
3166	if (! gf_IsNull(dataSetRow.get(info.column))) {
3167		var value = dataSetRow.get(info.column);
3168		var regExp = /^.*(?=.{9,15})(?=.*[a-zA-Z]).*$/;
3169
3170		var num = value.search(/[0-9]{1,}/i);
3171		var eng = value.search(/[a-z]{1,}/ig);
3172		//var spe = value.search(/[`~!@@#$%^&*|\\\'\";:\/?]{3,}/gi);
3173		var spe = value.search(/[\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]{1,}/gi);
3174
3175		var threeDigitRepeat  = /(\d)\1\1/;
3176		var threeWordRepeat   = /(\w)\1\1/;
3177		var threeSpeRepeat    = /(\W)\1\1/;
3178
3179		if(regExp.test(value)) {
3180			// 공백이 있는지 확인
3181			if ( value.search(/\s/) != -1 ) {
3182				return {
3183					"column" : info.column,
3184					"message" : "gw.err.passwordCantIncludeWhitespace"
3185				};
3186			}
3187			// 문자 숫자 특수문자로 구성되었는지 확인
3188			if ( num < 0 || eng < 0 || spe < 0) {
3189				return {
3190					"column" : info.column,
3191					"message" : "gw.err.passwordMustHaveMrT3AlphaNum"
3192				};
3193			}
3194
3195			// 동일 숫자가 3번 이상 반복 되는지
3196			if ( threeDigitRepeat.test(value) ) {
3197				return {
3198					"column" : info.column,
3199					"message" : "gw.err.passwordCantIncludeSuccessive3AlphaNum"
3200				};
3201			}
3202			// 동일 문자가 3번 이상 반복 되는지 확인
3203			if ( threeWordRepeat.test(value) ) {
3204				return {
3205					"column" : info.column,
3206					"message" : "gw.err.passwordCantIncludeSuccessive3AlphaNum"
3207				};
3208			}
3209
3210			// 동일 특수문자가 3번 이상 반복 되는지 확인
3211			if ( threeSpeRepeat.test(value) ) {
3212				return {
3213					"column" : info.column,
3214					"message" : "gw.err.passwordCantIncludeSuccessive3AlphaNum"
3215				};
3216			}
3217
3218			return null;
3219		} else {
3220			return {
3221				"column" : info.column,
3222				"message" : message
3223			};
3224		}
3225	} else {
3226		return null;
3227	}
3228};
3229
3230/**
3231 * 데이타셑 행의 특정 컬럼들의 최대 길이를 검증한다.
3232 * <pre>
3233 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3234 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3235 * </pre>
3236 * @param dataSetRow 상속을 검사대상 레코드
3237 * @param info validation 검증을 위한 부가정보 { column , title , message , maxLength } 객체임.
3238 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3239 * @author 김흥수
3240 * @since 2015-09-01
3241 * @version 1.0
3242 */
3243DataSet.DataSetRow.Validation.maxLength = function(dataSetRow, info) {
3244	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3245	var value = dataSetRow.get(info.column);
3246	var message = gf_Default(info.message, gf_GetMsg("gw.err.maxLength",[ title,info.maxLength ]));
3247	if (gf_IsNull(value)) {
3248		return null;
3249	} else if (gf_GetByteLength(value) <= info.maxLength) {
3250		return null;
3251	} else {
3252		return {
3253			"column" : info.column,
3254			"message" : message
3255		};
3256	}
3257};
3258
3259
3260/**
3261 * 데이타셑 행의 특정 컬럼들의 최소 길이를 검증한다.
3262 * <pre>
3263 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3264 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3265 * </pre>
3266 * @param dataSetRow 상속을 검사대상 레코드
3267 * @param info validation 검증을 위한 부가정보 { column , title , message , minLength } 객체임.
3268 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3269 * @author 김흥수
3270 * @since 2015-09-01
3271 * @version 1.0
3272 */
3273DataSet.DataSetRow.Validation.minLength = function(dataSetRow, info) {
3274	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3275	var value = dataSetRow.get(info.column);
3276	var message = gf_Default(info.message, gf_GetMsg("gw.err.minLength",[ title,info.minLength ]));
3277	if (gf_IsNull(value)) {
3278		return null;
3279	} else if (gf_GetByteLength(value) >= info.minLength) {
3280		return null;
3281	} else {
3282		return {
3283			"column" : info.column,
3284			"message" : message
3285		};
3286	}
3287};
3288
3289/**
3290 * 데이타셑 행의 특정 컬럼들의 사용자 id의 형태인지 를 검사한다. 영문 대소문자와  - _ 만을 허용한다.
3291 * <pre>
3292 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3293 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3294 * </pre>
3295 * @param dataSetRow 상속을 검사대상 레코드
3296 * @param info validation 검증을 위한 부가정보 { column , title , message  } 객체임.
3297 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3298 * @author 김흥수
3299 * @since 2015-09-01
3300 * @version 1.0
3301 */
3302DataSet.DataSetRow.Validation.checkUserId = function(dataSetRow, info) {
3303	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3304	var value = dataSetRow.get(info.column);
3305	var message = gf_Default(info.message, gf_GetMsg("gw.err.userId",[ title ]));
3306
3307	if (gf_IsNull(value)) {
3308		return null;
3309	} else {
3310
3311		for ( var i = 0; i < value.length; i++ )  {
3312			var val = value.charAt(i);
3313			var regexp = /[A-Za-z0-9]|[-_]/g;
3314			if ( regexp.test(val) ) {
3315				continue;
3316			}
3317			else {
3318				return {
3319					"column" : info.column,
3320					"message" : message
3321				};
3322			}
3323		}
3324		return null;
3325	}
3326};
3327
3328
3329
3330/**
3331 * 데이타셑 행의 특정 컬럼들의 최대입력 가능값을 검증한다.
3332 * <pre>
3333 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3334 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3335 * </pre>
3336 * @param dataSetRow 상속을 검사대상 레코드
3337 * @param info validation 검증을 위한 부가정보 { column , dataType , title , dataFormat , value , message } 객체임.
3338 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3339 * @author 김흥수
3340 * @since 2015-09-01
3341 * @version 1.0
3342 */
3343DataSet.DataSetRow.Validation.maxValue = function(dataSetRow, info) {
3344	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3345	var dataType = gf_Default(info.dataType, dataSetRow.getDataSet().fieldType(info.column));
3346	var fmt = gf_Default(info.dataFormat, dataSetRow.getDataSet().fieldFormat(info.column));
3347	var dataValue = info.value;
3348	if(gf_IsObjNull(dataValue)) {
3349		alert("value 속성은 반드시 설정하십시오.");
3350		throw "value 속성은 반드시 설정하십시오.";
3351	}
3352	var dispValue = dataValue;
3353	if(dataType == DataSet.DataType.DATE) {
3354		fmt = gf_Default(fmt,DataSet.DEFAULT_DATE_FORMAT);
3355		dispValue = dataValue.toDate(fmt).format(Date.__DISPLAY_FORMAT__);
3356	}
3357	var value = dataSetRow.get(info.column);
3358	var compareFunc = (function() {
3359		if(dataType == DataSet.DataType.NUMBER) {
3360			return function(a,b) {
3361				if(gf_IsNull(a)) return true;
3362				b = gf_GetNumber(b);
3363				a = gf_GetNumber(a);
3364				return a <= b;
3365			};
3366		} else if (dataType == DataSet.DataType.DECIMAL) {
3367			return function(a,b) {
3368				if(gf_IsNull(a)) return true;
3369				a = gf_GetDecimal(a);
3370				return a.isLE(b);
3371			};
3372		} else if (dataType == DataSet.DataType.DATE) {
3373			return function(a,b) {
3374				if(gf_IsNull(a)) return true;
3375				a = a.toDate(fmt).valueOf();
3376				b = b.toDate(fmt).valueOf();
3377				return a <= b;
3378			};
3379		} else {
3380			return function(a,b) {
3381				if(gf_IsNull(a)) return true;
3382				return a <= b;
3383			};
3384		}
3385	}());
3386	if (compareFunc(value,dataValue)) {
3387		return null;
3388	} else {
3389		var message = gf_Default(info.message, gf_GetMsg("gw.err.maxValue",[ title , dispValue  ]));
3390		return {
3391			"column" : info.column,
3392			"message" : message
3393		};
3394	}
3395};
3396
3397/**
3398 * 데이타셑 행의 특정 컬럼들의 최소입력 가능값을 검증한다.
3399 * <pre>
3400 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3401 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3402 * </pre>
3403 * @param dataSetRow 상속을 검사대상 레코드
3404 * @param info validation 검증을 위한 부가정보 { column , dataType , title , dataFormat , value , message } 객체임.
3405 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3406 * @author 김흥수
3407 * @since 2015-09-01
3408 * @version 1.0
3409 */
3410DataSet.DataSetRow.Validation.minValue = function(dataSetRow, info) {
3411	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3412	var dataType = gf_Default(info.dataType, dataSetRow.getDataSet().fieldType(info.column));
3413	var fmt = gf_Default(info.dataFormat, dataSetRow.getDataSet().fieldFormat(info.column));
3414	var dataValue = info.value;
3415	if(gf_IsObjNull(dataValue)) {
3416		alert("value 속성은 반드시 설정하십시오.");
3417		throw "value 속성은 반드시 설정하십시오.";
3418	}
3419	var dispValue = dataValue;
3420	if(dataType == DataSet.DataType.DATE) {
3421		fmt = gf_Default(fmt,DataSet.DEFAULT_DATE_FORMAT);
3422		dispValue = dataValue.toDate(fmt).format(Date.__DISPLAY_FORMAT__);
3423	}
3424	var value = dataSetRow.get(info.column);
3425	var compareFunc = (function() {
3426		if(dataType == DataSet.DataType.NUMBER) {
3427			return function(a,b) {
3428				if(gf_IsNull(a)) return true;
3429				b = gf_GetNumber(b);
3430				a = gf_GetNumber(a);
3431				return a >= b;
3432			};
3433		} else if (dataType == DataSet.DataType.DECIMAL) {
3434			return function(a,b) {
3435				if(gf_IsNull(a)) return true;
3436				a = gf_GetDecimal(a);
3437				return a.isGE(b);
3438			};
3439		} else if (dataType == DataSet.DataType.DATE) {
3440			return function(a,b) {
3441				if(gf_IsNull(a)) return true;
3442				a = a.toDate(fmt).valueOf();
3443				b = b.toDate(fmt).valueOf();
3444				return a >= b;
3445			};
3446		} else {
3447			return function(a,b) {
3448				if(gf_IsNull(a)) return true;
3449				return a >= b;
3450			};
3451		}
3452	}());
3453	if (compareFunc(value,dataValue)) {
3454		return null;
3455	} else {
3456		var message = gf_Default(info.message, gf_GetMsg("gw.err.minValue",[ title , dispValue  ]));
3457		return {
3458			"column" : info.column,
3459			"message" : message
3460		};
3461	}
3462};
3463
3464/**
3465 * 데이타셑 행의 특정 컬럼들의 날짜 기간의 유효성을 검증한다.
3466 * <pre>
3467 * info.column 보다 info.columnTo가 더 작으면 오류
3468 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3469 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3470 * </pre>
3471 * @param dataSetRow 상속을 검사대상 레코드
3472 * @param info validation 검증을 위한 부가정보 { column ,columnTo,  title , title2, dataFormat , message } 객체임.
3473 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3474 * @author 김흥수
3475 * @since 2015-09-01
3476 * @version 1.0
3477 */
3478DataSet.DataSetRow.Validation.dateTerm = function(dataSetRow, info) {
3479	var title1 = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3480	var title2 = gf_Default(info.title2, dataSetRow.getDataSet().fieldTitle(info.columnTo));
3481	var fmt = gf_Default(info.dataFormat, dataSetRow.getDataSet().fieldFormat(info.column));
3482	var value = dataSetRow.get(info.column);
3483	var value2 = dataSetRow.get(info.columnTo);
3484
3485	var compareFunc = function(a,b) {
3486		if(gf_IsNull(a)) return true;
3487		if(gf_IsNull(b)) return true;
3488		a = a.toDate(fmt).valueOf();
3489		b = b.toDate(fmt).valueOf();
3490		return a <= b;
3491	};
3492	if (compareFunc(value,value2)) {
3493		return null;
3494	} else {
3495		var message = gf_Default(info.message, gf_GetMsg("gw.err.dateTerm",[ title1 , title2  ]));
3496		return {
3497			"column" : info.column,
3498			"message" : message
3499		};
3500	}
3501};
3502
3503/**
3504 * 데이타셑 행의 특정 컬럼들의 숫자 기간의 유효성을 검증한다.
3505 * <pre>
3506 * info.column 보다 info.columnTo가 더 작으면 오류
3507 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3508 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3509 * </pre>
3510 * @param dataSetRow 상속을 검사대상 레코드
3511 * @param info validation 검증을 위한 부가정보 { column ,columnTo,  title , message } 객체임.
3512 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3513 * @author 김흥수
3514 * @since 2015-09-01
3515 * @version 1.0
3516 */
3517DataSet.DataSetRow.Validation.numberTerm = function(dataSetRow, info) {
3518	var title1 = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3519	var title2 = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.columnTo));
3520	var value = dataSetRow.get(info.column);
3521	var value2 = dataSetRow.get(info.columnTo);
3522
3523	var compareFunc = function(a,b) {
3524		if(gf_IsNull(a)) return true;
3525		if(gf_IsNull(b)) return true;
3526		a = gf_GetNumber(a);
3527		b = gf_GetNumber(b);
3528		return a <= b;
3529	};
3530	if (compareFunc(value,value2)) {
3531		return null;
3532	} else {
3533		var message = gf_Default(info.message, gf_GetMsg("gw.err.dateTerm",[ title1 , title2  ]));
3534		return {
3535			"column" : info.column,
3536			"message" : message
3537		};
3538	}
3539};
3540
3541/**
3542 * 컬럼의 유일성을 검증한다.
3543 * <pre>
3544 * checkValid 함수에 의해 호출되도록 작성되어 있으며
3545 * checkValid 함수에 의해 호출되는 함수는 function(dataSetRow, info) 의 스펙을 만족하여야 한다.
3546 * </pre>
3547 * @param dataSetRow 상속을 검사대상 레코드
3548 * @param info validation 검증을 위한 부가정보 { column , title , message , keys } 객체임.
3549 * @returns Object 정상인 경우 null 정상이 아닌 경우 {column,message} 객체를 리턴한다.
3550 * @author 김흥수
3551 * @since 2015-09-01
3552 * @version 1.0
3553 */
3554DataSet.DataSetRow.Validation.unique = function(dataSetRow, info) {
3555	var getKeyData = function(dataRow , keyList) {
3556		//return keyList.hvcMap(function(key){ return dataRow.get(key); }).join("@$@");
3557		return Array.prototype.hvcMap.call(keyList,function(key){ return dataRow.get(key); }).join("@$@");
3558	};
3559	var makeCheckUniqueData = function(dataSet , keys ) {
3560		var keyList = keys.split(",");
3561		var ret = {};
3562		dataSet.forEachInRows(function(dataRow){
3563			var keyData = getKeyData(dataRow,keyList);
3564			ret[keyData] = gf_Default(ret[keyData],0) + 1;
3565		});
3566		return ret;
3567	};
3568	var title = gf_Default(info.title, dataSetRow.getDataSet().fieldTitle(info.column));
3569	var message = gf_Default(info.message, gf_GetMsg("gw.err.dup",[ title ]));
3570	console.log(info);
3571	if(gf_IsObjNull(info.keys)) {
3572		alert("unique 설정시에는 반드시 keys 속성을 설정하십시오.ex)keys:'a,b,c' ");
3573		throw "unique 설정시에는 반드시 keys 속성을 설정하십시오.ex)keys:'a,b,c' ";
3574	}
3575	var uniqueData = dataSetRow.getDataSet().getValidatorData("unique");
3576	var uniqueSearchData = null;
3577	if(gf_IsObjNull(uniqueData)) {
3578		uniqueData = {};
3579		uniqueSearchData = makeCheckUniqueData(dataSetRow.getDataSet(),info.keys);
3580		uniqueData[info.keys] = uniqueSearchData;
3581		dataSetRow.getDataSet().setValidatorData("unique",uniqueData);
3582	} else {
3583		uniqueSearchData = uniqueData[info.keys];
3584		if(gf_IsObjNull(uniqueSearchData)) {
3585			uniqueSearchData = makeCheckUniqueData(dataSetRow.getDataSet(),info.keys);
3586			uniqueData[info.keys] = uniqueSearchData;
3587		}
3588	}
3589	var keyList = info.keys.split(",");
3590	var keyData = getKeyData(dataSetRow,keyList);
3591
3592	if (uniqueSearchData[keyData] > 1 ) {
3593		return {
3594			"column" : info.column,
3595			"message" : message
3596		};
3597	} else {
3598		return null;
3599	}
3600};
3601
3602/**
3603 * 데이타셑의 행별 유효성을 검증한다.
3604 *
3605 * @param validations validator 정보 배열
3606 * @returns boolean 정상이면 true 비정상이면 false
3607 * @author 김흥수
3608 * @since 2015-09-01
3609 * @version 1.0
3610 */
3611DataSet.DataSetRow.prototype.checkValid = function(validations) {
3612	var ret = null;
3613	var that = this;
3614
3615	//validations.forEachStoppable(function(validation) {
3616	Array.prototype.forEachStoppable.call(validations,function(validation) {
3617		var validator = validation.validator;
3618		if (typeof (validator) == "string") {
3619			validator = DataSet.DataSetRow.Validation[validator];
3620		}
3621		if(gf_IsObjNull(validator)) {
3622			return false;
3623		}
3624		//validation.infos.forEachStoppable(function(info) {
3625		Array.prototype.forEachStoppable.call(validation.infos,function(info) {
3626			ret = validator.call(null, that, info);
3627			if (gf_IsObjNull(ret)) {
3628				return false;
3629			} else {
3630				return true;
3631			}
3632		});
3633		if (gf_IsObjNull(ret)) {
3634			return false;
3635		} else {
3636			return true;
3637		}
3638	});
3639
3640	return ret;
3641};
3642
3643/**
3644 * 데이터Row의 특정 컬럼 값을 수정함
3645 *
3646 * @param key 컬럼명
3647 * @param value 설정할 값
3648 * @param index framework 내에서만 사용하는 숨겨진 변수 데이타셑 내의 행 인덱스이다. 기본적으로는 설정하면 안된다. 만약 설정할 경우 반드시 해당 행번호이어야만 한다.
3649 * @author Jun.
3650 * @since 2013-03-28
3651 * @version 1.0
3652 */
3653DataSet.DataSetRow.prototype.set = function(key, value, index) {
3654	var columns = this._dataSet._columns;
3655	var oldValue = this._data[key];
3656
3657	if (!columns.hasColumn(key)) {
3658		return;
3659	} else if (value == this._data[key])
3660		return;
3661	else if (value != this._data[key] && this._orgData == null) {
3662		this._orgData = DataSet.Util.objectClone(this._data);
3663		this._data = DataSet.Util.objectClone(this._orgData);
3664	}
3665
3666	this._data[key] = value;
3667
3668	if (!columns.virtualField(key)) {
3669		this.setChangedStatus();
3670	}
3671
3672	if (this.equals() && this.getStatus() == DataSet.DataSetStatus.UPDATE ) {
3673		this._orgData = null;
3674		this.setStatus(DataSet.DataSetStatus.NORMAL);
3675	}
3676	if (!this._dataSet.suppressEvent) {
3677		if (gf_IsObjNull(index)) {
3678			index = this._dataSet.getRowIndexInView(this);
3679		}
3680		if (index < 0)
3681			return;
3682		this._dataSet.fireValueChanged(index, key, oldValue, value);
3683	}
3684};
3685
3686/**
3687 * 현재 데이터와 오리지널 데이터를 비교함
3688 *
3689 * @returns equals(boolean)
3690 * @author Jun.
3691 * @since 2013-03-28
3692 * @version 1.0
3693 */
3694DataSet.DataSetRow.prototype.equals = function() {
3695	if (this._orgData == null)
3696		return true;
3697	for ( var key in this._data) {
3698		if (! (( gf_IsNull(this._data[key]) && gf_IsNull(this._orgData[key])) || ( this._data[key] == this._orgData[key])) )
3699			return false;
3700	}
3701	return true;
3702};
3703
3704/**
3705 * 데이터Row의 상태를 변경함 ADD된 데이터일 경우는 삭제 되기 전까지 INSERT임.
3706 *
3707 * @param status 행상태를 설정한다. (DataSet.DataSetStatus)
3708 * @author Jun.
3709 * @since 2013-03-28
3710 * @version 1.0
3711 */
3712DataSet.DataSetRow.prototype.setStatus = function(status) {
3713	this._rowStatus = status;
3714};
3715
3716/**
3717 * 데이터Row의 상태를 변경 상태로 변경함
3718 *
3719 * @author Jun.
3720 * @since 2013-03-28
3721 * @version 1.0
3722 */
3723DataSet.DataSetRow.prototype.setChangedStatus = function() {
3724	if (this._rowStatus != DataSet.DataSetStatus.INSERT)
3725		this._rowStatus = DataSet.DataSetStatus.UPDATE;
3726};
3727
3728/**
3729 * 데이터Row의 상태가 생성 상태인가?
3730 *
3731 * @returns boolean 생성상태이면 true
3732 * @author 김흥수
3733 * @since 2015-10-07
3734 * @version 1.0
3735 */
3736DataSet.DataSetRow.prototype.isNew = function() {
3737	return this._rowStatus == DataSet.DataSetStatus.INSERT;
3738};
3739
3740/**
3741 * 데이터Row의 상태가 보통 상태인가?
3742 *
3743 * @returns boolean Normal 상태이면 true
3744 * @author 김흥수
3745 * @since 2015-10-07
3746 * @version 1.0
3747 */
3748DataSet.DataSetRow.prototype.isNormal = function() {
3749	return this._rowStatus == DataSet.DataSetStatus.NORMAL;
3750};
3751
3752/**
3753 * 데이터Row의 상태가 수정 상태인가?
3754 *
3755 * @returns boolean Update 상태이면 true
3756 * @author 김흥수
3757 * @since 2015-10-07
3758 * @version 1.0
3759 */
3760DataSet.DataSetRow.prototype.isUpdated = function() {
3761	return this._rowStatus == DataSet.DataSetStatus.UPDATE;
3762};
3763
3764/**
3765 * 데이터Row의 상태가 삭제 상태인가?
3766 *
3767 * @returns boolean Delete 상태이면 true
3768 * @author 김흥수
3769 * @since 2015-10-07
3770 * @version 1.0
3771 */
3772DataSet.DataSetRow.prototype.isDeleted = function() {
3773	return this._rowStatus == DataSet.DataSetStatus.DELETE;
3774};
3775
3776/**
3777 * 데이터Row의 상태가 변경 상태(신규 또는 수정)인가?
3778 *
3779 * @returns boolean return this.isNew() || this.isUpdated();
3780 * @author 김흥수
3781 * @since 2015-10-07
3782 * @version 1.0
3783 */
3784DataSet.DataSetRow.prototype.isChanged = function() {
3785	return this.isNew() || this.isUpdated();
3786};
3787
3788/**
3789 * 데이터Row의 상태를 출력함.
3790 *
3791 * @returns status 데이타 행의 행상태 (DataSet.DataSetStatus)
3792 * @author Jun.
3793 * @since 2013-03-28
3794 * @version 1.0
3795 */
3796DataSet.DataSetRow.prototype.getStatus = function() {
3797	return this._rowStatus;
3798};
3799
3800/**
3801 * 데이터Row의 데이타셑을 리턴한다.
3802 *
3803 * @returns DataSet
3804 * @author 김흥수
3805 * @since 2015-09-01
3806 * @version 1.0
3807 */
3808DataSet.DataSetRow.prototype.getDataSet = function() {
3809	return this._dataSet;
3810};
3811
3812/**
3813 * 데이터Row의 특정 컬럼 값을 출력함.
3814 *
3815 * @param key 컬럼명(만약 생략되면 행 전체의 객체형을 리턴)
3816 * @returns value 컬럼 또는 행의 값
3817 * @author Jun.
3818 * @since 2013-03-28
3819 * @version 1.0
3820 */
3821DataSet.DataSetRow.prototype.get = function(key) {
3822
3823	if (gf_IsObjNull(key))
3824		return this._getColToData(this._data);
3825
3826	if (!this._dataSet._columns.hasColumn(key)) {
3827		return;
3828	}
3829
3830	return gf_IsObjNull(this._data[key]) ? "" : this._data[key];
3831};
3832
3833/**
3834 * 데이터Row의 컬럼들의 현재 값을 객체형태로 리턴
3835 *
3836 * @returns Object
3837 * @author Jun.
3838 * @since 2013-03-28
3839 * @version 1.0
3840 */
3841DataSet.DataSetRow.prototype.getCurrentData = function() {
3842	return this._getColToData(this._data, true);
3843};
3844
3845/**
3846 * 데이터Row의 컬럼들의 현재 값을 객체형태로 리턴
3847 * 내부적으로만 사용해야 한다.
3848 *
3849 * @returns Object
3850 * @author Jun.
3851 * @since 2013-03-28
3852 * @version 1.0
3853 */
3854DataSet.DataSetRow.prototype._getColToData = function(data, withDefined) {
3855	withDefined = withDefined || false;
3856	var cols = this._dataSet._columns.getColumns();
3857
3858	if (cols == null) {
3859		var retData = DataSet.Util.objectClone(data);
3860		delete retData["_dataSetRow"];
3861		return retData;
3862	} else {
3863		var ret = cols.reduce(function(rsl, col) {
3864			if (!withDefined || typeof (data[col]) != "undefined") {
3865				rsl[col] = gf_IsObjNull(data[col]) ? "" : data[col];
3866			}
3867			return rsl;
3868		}, {});
3869		ret[DataSet.RowIdColumn] = data[DataSet.RowIdColumn];
3870		return ret;
3871	}
3872
3873};
3874
3875/**
3876 * 데이터Row를 복사하여 출력함.
3877 *
3878 * @returns Object
3879 * @author Jun.
3880 * @since 2013-03-28
3881 * @version 1.0
3882 */
3883DataSet.DataSetRow.prototype.clone = function() {
3884	var data = this._getColToData(this._data);
3885
3886	return DataSet.Util.objectClone(data);
3887};
3888
3889/**
3890 * 데이터Row의 특정 컬럼의 오리지널 값을 출력함
3891 *
3892 * @param key 컬럼명
3893 * @returns value 오리지날 값
3894 * @author Jun.
3895 * @since 2013-03-28
3896 * @version 1.0
3897 */
3898DataSet.DataSetRow.prototype.getOrg = function(key) {
3899	if (typeof (key) == "undefined") {
3900		var data = (this._orgData == null) ? this._data : this._orgData;
3901		return this._getColToData(data);
3902	}
3903
3904	return (this._orgData == null) ? this._data[key] : this._orgData[key];
3905};
3906
3907/**
3908 * 데이터 Row를 삭제함. 상태값만 변경
3909 *
3910 * @author Jun.
3911 * @since 2013-03-28
3912 * @version 1.0
3913 */
3914DataSet.DataSetRow.prototype.remove = function() {
3915	this._rowStatus = DataSet.DataSetStatus.DELETE;
3916};
3917
3918/**
3919 * 데이터 RowStatus를 초기화하고 오리지널 데이터를 삭제.
3920 *
3921 * @author Jun.
3922 * @since 2013-03-28
3923 * @version 1.0
3924 */
3925DataSet.DataSetRow.prototype.apply = function() {
3926	this._rowStatus = DataSet.DataSetStatus.NORMAL;
3927	this._orgData = null;
3928};
3929
3930/**
3931 * 데이터 Row를 처음 상태로 되돌림.
3932 *
3933 * @author Jun.
3934 * @since 2013-03-28
3935 * @version 1.0
3936 */
3937DataSet.DataSetRow.prototype.reset = function() {
3938	if (this._rowStatus == DataSet.DataSetStatus.INSERT)
3939		return;
3940
3941	this._rowStatus = DataSet.DataSetStatus.NORMAL;
3942	this._data = this.getOrg();
3943	this._orgData = null;
3944};
3945
3946/**
3947 * @class 데이터셑 Column
3948 * @param columnId 컬럼명
3949 * @param dataType 데이타 타입(기본값은 STRING)
3950 * @param columnTitle 컬럼 타이틀(기본값은 columnId)
3951 * @param fmt 저장데이타 형식 (날짜 형식 외에는 의미 없슴)
3952 * @param virtual 가상여부
3953 * @param maxLength 최대길이
3954 * @param dispFmt 출력형식
3955 * @returns this{DataSet.DataSetColumn}
3956 * @author 김흥수
3957 * @since 2015-09-04
3958 * @version 1.0
3959 */
3960DataSet.DataSetColumn = function(columnId, dataType, columnTitle, fmt, virtual,maxLength,dispFmt) {
3961	this.columnId = columnId;
3962	this.dataType = gf_IsObjNull(dataType) ? DataSet.DataType.STRING
3963			: DataSet.DataType.fromString(dataType);
3964	this.columnTitle = gf_IsObjNull(columnTitle) ? columnId : columnTitle;
3965	this.fmt = gf_IsObjNull(fmt) && this.dataType == DataSet.DataType.DATE ? DataSet.DEFAULT_DATE_FORMAT : fmt;
3966	this.isVirtual = gf_IsObjNull(virtual) ? false : (virtual === true
3967			|| virtual === false ? virtual : false);
3968	this.maxLength = gf_Default(maxLength,-1);
3969	this.dispFmt = gf_IsObjNull(dispFmt) && this.dataType == DataSet.DataType.DATE ? Date.__DISPLAY_FORMAT__ : dispFmt;
3970};
3971
3972/**
3973 * 필드명을 리턴한다.
3974 * @returns String 필드명
3975 * @author 김흥수
3976 * @since 2015-09-01
3977 * @version 1.0
3978 */
3979DataSet.DataSetColumn.prototype.fieldName = function() {
3980	return this.columnId;
3981};
3982
3983/**
3984 * 데이타 타입을 리턴하거나 설정한다.
3985 * 만약 첫번째 인자가 있으면 그 인자로 데이타 타입이 설정된다.
3986 * @param arg 데이타 타입
3987 * @returns String datatype
3988 * @author 김흥수
3989 * @since 2015-09-01
3990 * @version 1.0
3991 */
3992DataSet.DataSetColumn.prototype.fieldType = function() {
3993	if (arguments[0] != undefined) {
3994		this.dataType = arguments[0];
3995		if (this.dataType == DataSet.DataType.DATE && gf_IsObjNull(this.fmt)) {
3996			this.fmt = DataSet.DEFAULT_DATE_FORMAT;
3997		}
3998	}
3999	return this.dataType;
4000};
4001
4002/**
4003 * 데이타 길이를 리턴하거나 설정한다.
4004 * 만약 첫번째 인자가 있으면 그 인자로 데이타 길이가 설정된다.
4005 * @param arg 데이타 길이
4006 * @returns Number 데이타 길이
4007 * @author 김흥수
4008 * @since 2015-09-01
4009 * @version 1.0
4010 */
4011DataSet.DataSetColumn.prototype.fieldLength = function() {
4012	if (arguments[0] != undefined) {
4013		if (this.dataType != DataSet.DataType.DATE ) {
4014			this.maxLength = arguments[0];
4015		}
4016	}
4017	return this.maxLength;
4018};
4019
4020/**
4021 * 가상 컬럼 여부를 리턴하거나 설정한다.
4022 * 만약 첫번째 인자가 있으면 그 인자로 가상 컬럼 여부가 설정된다.
4023 * @param arg 가상 컬럼 여부
4024 * @returns boolean 가상 컬럼 여부
4025 * @author 김흥수
4026 * @since 2015-09-01
4027 * @version 1.0
4028 */
4029DataSet.DataSetColumn.prototype.virtualField = function() {
4030	if (arguments[0] != undefined) {
4031		this.isVirtual = arguments[0];
4032	}
4033	return this.isVirtual;
4034};
4035
4036/**
4037 * 핑드 타이틀을 리턴하거나 설정한다.
4038 * 만약 첫번째 인자가 있으면 그 인자로 핑드 타이틀이 설정된다.
4039 * @param arg 핑드 타이틀
4040 * @returns String 핑드 타이틀
4041 * @author 김흥수
4042 * @since 2015-09-01
4043 * @version 1.0
4044 */
4045DataSet.DataSetColumn.prototype.fieldTitle = function() {
4046	if (arguments[0] != undefined) {
4047		this.columnTitle = arguments[0];
4048	}
4049	return this.columnTitle;
4050};
4051
4052/**
4053 * 핑드 형식을 리턴하거나 설정한다.
4054 * 만약 첫번째 인자가 있으면 그 인자로 핑드 형식이 설정된다.
4055 * @param arg 핑드 형식
4056 * @returns String 핑드 형식
4057 * @author 김흥수
4058 * @since 2015-09-01
4059 * @version 1.0
4060 */
4061DataSet.DataSetColumn.prototype.fieldFormat = function() {
4062	if (arguments[0] != undefined) {
4063		this.fmt = arguments[0];
4064	}
4065	return this.fmt;
4066};
4067
4068/**
4069 * 핑드 표시 형식을 리턴하거나 설정한다.
4070 * 만약 첫번째 인자가 있으면 그 인자로 핑드 표시 형식이 설정된다.
4071 * @param arg 핑드 표시 형식
4072 * @returns String 핑드 표시 형식
4073 * @author 김흥수
4074 * @since 2015-09-01
4075 * @version 1.0
4076 */
4077DataSet.DataSetColumn.prototype.fieldDisplayFormat = function() {
4078	if (arguments[0] != undefined) {
4079		this.dispFmt = arguments[0];
4080	}
4081	return this.dispFmt;
4082};
4083
4084/**
4085 * @class 컬럼의 단축 생성자들(문자열용)
4086 * @param columnId 컬럼명
4087 * @param columnTitle 컬럼 타이틀(기본값은 columnId)
4088 * @returns this{DataSet.DataSetColumn}
4089 * @author 김흥수
4090 * @since 2015-09-04
4091 * @version 1.0
4092 */
4093strC = function(columnId, columnTitle) {
4094	return new DataSet.DataSetColumn(columnId, DataSet.DataType.STRING,
4095			columnTitle);
4096};
4097/**
4098 * @class 컬럼의 단축 생성자들(숫자용)
4099 * @param columnId 컬럼명
4100 * @param columnTitle 컬럼 타이틀(기본값은 columnId)
4101 * @returns this{DataSet.DataSetColumn}
4102 * @author 김흥수
4103 * @since 2015-09-04
4104 * @version 1.0
4105 */
4106numC = function(columnId, columnTitle) {
4107	return new DataSet.DataSetColumn(columnId, DataSet.DataType.NUMBER,
4108			columnTitle);
4109};
4110/**
4111 * @class 컬럼의 단축 생성자들(숫자용)
4112 * @param columnId 컬럼명
4113 * @param columnTitle 컬럼 타이틀(기본값은 columnId)
4114 * @returns this{DataSet.DataSetColumn}
4115 * @author 김흥수
4116 * @since 2015-09-04
4117 * @version 1.0
4118 */
4119decimalC = function(columnId, columnTitle) {
4120	return new DataSet.DataSetColumn(columnId, DataSet.DataType.DECIMAL,
4121			columnTitle);
4122};
4123/**
4124 * @class 컬럼의 단축 생성자들(날짜용)
4125 * @param columnId 컬럼명
4126 * @param columnTitle 컬럼 타이틀(기본값은 columnId)
4127 * @param fmt 날짜 컬럼의 기본 저장 형식
4128 * @returns this{DataSet.DataSetColumn}
4129 * @author 김흥수
4130 * @since 2015-09-04
4131 * @version 1.0
4132 */
4133dateC = function(columnId, columnTitle, fmt) {
4134	return new DataSet.DataSetColumn(columnId, DataSet.DataType.DATE,
4135			columnTitle, fmt);
4136};
4137
4138/**
4139 * @class 데이터셑 Columns
4140 * @param JSONObject
4141 * @returns this{DataSet.DataSetColumns}
4142 * @author Jun.
4143 * @since 2013-03-28
4144 * @version 1.0
4145 */
4146DataSet.DataSetColumns = function(columns) {
4147	this.setColumns(columns);
4148};
4149
4150/**
4151 * 일반 리스트로부터 컬럼 목록을 생성한다
4152 *
4153 * @param 객체의
4154 *            배열
4155 * @returns DataSet.DataSetColumns
4156 * @author Jun.
4157 * @since 2013-03-28
4158 * @version 1.0
4159 */
4160DataSet.DataSetColumns.makeFromList = function(list) {
4161	return (new DataSet.DataSetColumns()).setColumnsFromObjectList(list);
4162};
4163
4164DataSet.DataSetColumns.prototype = {
4165
4166	/**
4167	 * 서버에 전송할 메타정보를 생성한다.
4168	 *
4169	 * @param dataSetId 서버에서 사용될 데이타셑의 id
4170	 * @author 김흥수
4171	 * @since 2015-10-12
4172	 * @version 1.2
4173	 */
4174	makeMetaInfo : function(dataSetId) {
4175		if (gf_IsObjNull(this._columns)) {
4176			return [];
4177		}
4178		var conditionF = function(elem){ return ! elem.virtualField();};
4179		var extractF = function(elem){
4180			return {
4181				"dataSetId" : dataSetId
4182				,"fieldName" : elem.fieldName()
4183				,"fieldType" : elem.fieldType()
4184				,"fieldLength" : elem.fieldLength()
4185				,"fieldTitle" : elem.fieldTitle()
4186				,"fieldFormat" : elem.fieldFormat()
4187				,"fieldDisplayFormat" : elem.fieldDisplayFormat()
4188			};
4189		};
4190		var ret = Array.prototype.mapIf.call(this._columns,extractF,conditionF);
4191		return ret;
4192	},
4193
4194	/**
4195	 * 데이터Columns를 설정함.
4196	 *
4197	 * @param columns 컬럼 정보 배열
4198	 * <pre>
4199     *        columns의 종류는 총 4가지가 가능하다.
4200     *        1) 컬럼명의 문자열 배열
4201     *           ex) ["column1","column2","column3"]
4202     *        2) DataSet.DataSetColumn 의 배열
4203     *           ex) [ new DataSet.DataSetColumn("column1", DataSet.DataType.STRING, "컬럼1") , new DataSet.DataSetColumn("column2", DataSet.DataType.DATE, "컬럼2", "YYYYMMDD", false,null,"YYYY-MM-DD") ]
4204     *        3) json 객체 배열 (객체의 가능한 속성은 columnId , dataType , columnTitle , fmt , isVirtual , maxLength , dispFmt 이다 )
4205     *           ex) [ {"columnId":"column1" , "dataType" : DataSet.DataType.STRING , "columnTitle":"컬럼1" } , {"columnId":"column2" , "dataType" : DataSet.DataType.DATE , "columnTitle":"컬럼2" , "fmt" : "YYYYMMDD" , "dispFmt" : "YYYY-MM-DD" }  ]
4206     *        4) json 객체 ( 필드명을 키로 하고 컬럼 정보를 속성으로 하는 json 객체이다. 컬럼 정보의 속성은 fieldType , fieldTitle , fieldFormat , virtualField , fieldLength , fieldDisplayFormat 이 가능하다. )
4207     *           ex) { "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" }
4207 , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }
4208     * </pre>
4209	 * @author Jun.
4210	 * @since 2013-11-18
4211	 * @version 1.2
4212	 */
4213	setColumns : function(columns) {
4214		if (gf_IsObjNull(columns)) {
4215			this._columns = null;
4216			this._columnNames = null;
4217			this._columnNameArray = null;
4218			return;
4219		}
4220		if (columns instanceof Array) {
4221			if (typeof (columns[0]) == "string") {
4222				this._setColumnsFromStringArray(columns);
4223			} else if (columns[0] instanceof DataSet.DataSetColumn) {
4224				this._setColumnsFromDataSetColumns(columns);
4225			} else  {
4226				this._setColumnsFromJsonColumns(columns);
4227			}
4228		} else {
4229			this._setColumnsFromDescs(columns);
4230		}
4231	},
4232
4233	/**
4234	 * 데이타셑의 컬럼명 배열을 리턴함
4235	 *
4236	 * @returns Array 컬럼명의 배열
4237	 * @author Jun.
4238	 * @since 2013-11-18
4239	 * @version 1.2
4240	 */
4241	getColumns : function() {
4242		return this._columnNameArray;
4243	},
4244
4245	/**
4246	 * 컬럼정보의 배열을 구한다.
4247	 * DataSet.DataSetColumn의 배열을 리턴함
4248	 *
4249	 * @returns DataSet.DataSetColumn []
4250	 * @author 김흥수
4251	 * @since 2015-09-04
4252	 * @version 1.2
4253	 */
4254	getColumnInfos : function() {
4255		return this._columns;
4256	},
4257
4258	/**
4259	 * DataSet.DataSetColumn 정보를 구한다.
4260	 *
4261	 * @param id(number 또는 string)
4262	 * @returns DataSet.DataSetColumn
4263	 * @author 김흥수
4264	 * @since 2015-09-04
4265	 * @version 1.2
4266	 */
4267	getColumnInfo : function(id) {
4268		if (typeof id == "number") {
4269			try {
4270				return this._columns[id];
4271			} catch(e) { return null; }
4272
4273		} else {
4274			try {
4275				return this._columns[this._columnNames[id]];
4276			} catch(e) { return null; }
4277		}
4278	},
4279
4280	/**
4281	 * 특정 컬럼 인덱스의 컬럼명을 구한다.
4282	 *
4283	 * @param id(number 또는 string)
4284	 * @returns 컬럼명
4285	 * @author 김흥수
4286	 * @since 2015-09-04
4287	 * @version 1.2
4288	 */
4289	fieldName : function(id) {
4290		if (gf_IsObjNull(id)) {
4291			return this._columnNameArray;
4292		} else {
4293			var colInfo = this.getColumnInfo(id);
4294			if (gf_IsObjNull(colInfo))
4295				return null;
4296			return colInfo.fieldName();
4297		}
4298	},
4299
4300	/**
4301	 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 타입을 구하거나 설정한다.
4302	 *
4303	 * @param id(number 또는 string)
4304	 * @param v 컬럼 데이타 타입
4305	 * @returns 컬럼 데이타 타입
4306	 * @author 김흥수
4307	 * @since 2015-09-04
4308	 * @version 1.2
4309	 */
4310	fieldType : function(id, v) {
4311		var colInfo = this.getColumnInfo(id);
4312		if (gf_IsObjNull(colInfo))
4313			return null;
4314		return colInfo.fieldType(v);
4315	},
4316
4317	/**
4318	 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 길이를 구하거나 설정한다.
4319	 *
4320	 * @param id(number 또는 string)
4321	 * @param v 컬럼 데이타 길이
4322	 * @returns 컬럼 데이타 길이
4323	 * @author 김흥수
4324	 * @since 2015-10-15
4325	 * @version 1.2
4326	 */
4327	fieldLength : function(id, v) {
4328		var colInfo = this.getColumnInfo(id);
4329		if (gf_IsObjNull(colInfo))
4330			return null;
4331		return colInfo.fieldLength(v);
4332	},
4333
4334	/**
4335	 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼의 가상여부를 구하거나 설정한다.
4336	 *
4337	 * @param id(number 또는 string)
4338	 * @param v 컬럼 데이타 타입
4339	 * @returns 컬럼 데이타 타입
4340	 * @author 김흥수
4341	 * @since 2015-09-04
4342	 * @version 1.2
4343	 */
4344	virtualField : function(id, v) {
4345		var colInfo = this.getColumnInfo(id);
4346		if (gf_IsObjNull(colInfo))
4347			return null;
4348		return colInfo.virtualField(v);
4349	},
4350
4351	/**
4352	 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 타이틀을 구하거나 설정한다.
4353	 *
4354	 * @param id(number 또는 string)
4355	 * @param v 컬럼 타이틀
4356	 * @returns 컬럼 타이틀
4357	 * @author 김흥수
4358	 * @since 2015-09-04
4359	 * @version 1.2
4360	 */
4361	fieldTitle : function(id, v) {
4362		var colInfo = this.getColumnInfo(id);
4363		if (gf_IsObjNull(colInfo))
4364			return null;
4365		return colInfo.fieldTitle(v);
4366	},
4367
4368	/**
4369	 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 형식을 구하거나 설정한다.
4370	 *
4371	 * @param id(number 또는 string)
4372	 * @param v 컬럼 데이타 형식
4373	 * @returns 컬럼 데이타 형식
4374	 * @author 김흥수
4375	 * @since 2015-09-04
4376	 * @version 1.2
4377	 */
4378	fieldFormat : function(id, v) {
4379		var colInfo = this.getColumnInfo(id);
4380		if (gf_IsObjNull(colInfo))
4381			return null;
4382		return colInfo.fieldFormat(v);
4383	},
4384
4385	/**
4386	 * 특정 컬럼 인덱스(또는 컬럼명)의 컬럼 데이타 형식을 구하거나 설정한다.
4387	 *
4388	 * @param id(number 또는 string)
4389	 * @param v 컬럼 데이타 형식
4390	 * @returns 컬럼 데이타 형식
4391	 * @author 김흥수
4392	 * @since 2015-09-04
4393	 * @version 1.2
4394	 */
4395	fieldDisplayFormat : function(id, v) {
4396		var colInfo = this.getColumnInfo(id);
4397		if (gf_IsObjNull(colInfo))
4398			return null;
4399		return colInfo.fieldDisplayFormat(v);
4400	},
4401
4402	/**
4403	 * 데이터Columns 갯수를 구함
4404	 *
4405	 * @returns length
4406	 * @author 김흥수
4407	 * @since 2015-09-04
4408	 * @version 1.2
4409	 */
4410	size : function() {
4411		return this._columns.length;
4412	},
4413
4414	/**
4415	 * 해당 컬럼명이 존재하는가?
4416	 *
4417	 * @param key 컬럼명
4418	 * @returns boolean
4419	 * @author Jun.
4420	 * @since 2013-11-18
4421	 * @version 1.2
4422	 */
4423	isColumn : function(key) {
4424		return this.hasColumn(key);
4425	},
4426	/**
4427	 * 해당 컬럼명이 존재하는가?
4428	 *
4429	 * @param key 컬럼명
4430	 * @returns boolean
4431	 * @author Jun.
4432	 * @since 2013-11-18
4433	 * @version 1.2
4434	 */
4435	hasColumn : function(key) {
4436		if (this._columns == null || this._columns.length == 0 )
4437			return true;
4438		return !gf_IsObjNull(this._columnNames[key])
4439				|| key == DataSet.RowIdColumn;
4440	},
4441	/**
4442	 * 데이타 목록을 사용하여 columns를 설정한다.
4443	 *
4444     * @param list 객체 배열
4445	 * @author Jun.
4446	 * @since 2013-11-18
4447	 * @version 1.2
4448	 */
4449	setColumnsFromObjectList : function(list) {
4450		if (gf_IsObjNull(list))
4451			return;
4452		if (list.length < 1)
4453			return;
4454		var columns = [];
4455		var row = list[0];
4456		for ( var fieldName in row) {
4457			columns.push(fieldName);
4458		}
4459		this._setColumnsFromStringArray(columns);
4460		return this;
4461	},
4462	/**
4463	 * 컬럼명의 배열을 사용하여 columns를 설정한다.
4464	 *
4465     * @param columns 컬럼명 배열
4466     * @author 김흥수
4467     * @since 2015-09-01
4468     * @version 1.0
4469	 */
4470	_setColumnsFromStringArray : function(columns) {
4471		var columnNames = {};
4472		//this._columns = columns.hvcMap(function(columnId, idx) {
4473		this._columns = Array.prototype.hvcMap.call(columns,function(columnId, idx) {
4474			if (!gf_IsObjNull(columnNames[columnId])) {
4475				throw "컬럼명이 중복되었습니다. (" + columnId + ")";
4476			}
4477			columnNames[columnId] = idx;
4478			return strC(columnId);
4479		});
4480		this._columnNameArray = columns;
4481		this._columnNames = columnNames;
4482	},
4483	/**
4484	 * DataSet.DataSetColumn 배열을 사용하여 columns를 설정한다.
4485	 *
4486     * @param columns DataSet.DataSetColumn 배열
4487     * @author 김흥수
4488     * @since 2015-09-01
4489     * @version 1.0
4490	 */
4491	_setColumnsFromDataSetColumns : function(columns) {
4492		var columnNames = {};
4493		var columnArray = [];
4494		//this._columns = columns.hvcMap(function(dataSetColumn, idx) {
4495		this._columns = Array.prototype.hvcMap.call(columns,function(dataSetColumn, idx) {
4496			if (!gf_IsObjNull(columnNames[dataSetColumn.fieldName()])) {
4497				throw "컬럼명이 중복되었습니다.";
4498			}
4499			columnNames[dataSetColumn.fieldName()] = idx;
4500			columnArray.push(dataSetColumn.fieldName());
4501			return dataSetColumn;
4502		});
4503		this._columnNameArray = columnArray;
4504		this._columnNames = columnNames;
4505	},
4506	/**
4507	 * 컬럼정보 객체 배열을 사용하여 columns를 설정한다.
4508     * @param columns 컬럼정보 객체 배열 객체 속성은 {columnId , dataType , columnTitle , fmt , isVirtual , maxLength , dispFmt}
4509     * @author 김흥수
4510     * @since 2015-09-01
4511     * @version 1.0
4512	 */
4513	_setColumnsFromJsonColumns : function(columns) {
4514		var columnNames = {};
4515		var columnArray = [];
4516		//this._columns = columns.hvcMap(function(dataSetColumn, idx) {
4517		this._columns = Array.prototype.hvcMap.call(columns,function(dataSetColumn, idx) {
4518			if (!gf_IsObjNull(columnNames[dataSetColumn.columnId])) {
4519				throw "컬럼명이 중복되었습니다.";
4520			}
4521			columnNames[dataSetColumn.columnId] = idx;
4522			columnArray.push(dataSetColumn.columnId);
4523			return new DataSet.DataSetColumn(dataSetColumn.columnId,
4524					dataSetColumn.dataType, dataSetColumn.columnTitle,
4525					dataSetColumn.fmt, dataSetColumn.isVirtual, dataSetColumn.maxLength, dataSetColumn.dispFmt);
4526		});
4527		this._columnNameArray = columnArray;
4528		this._columnNames = columnNames;
4529	},
4530	/**
4531	 * 컬럼정보를 사용하여 columns를 설정한다.
4532     * @param columns 컬럼명을 키로 하는 컬럼정보  컬럼정보의 속성은 {fieldType , fieldTitle , fieldFormat , virtualField , fieldLength , fieldDisplayFormat} 이다.
4533     *         ex) { "column1" : {"fieldType" : DataSet.DataType.STRING, "fieldTitle" : "컬럼1" }
4533 , "column2" : {"fieldType" : DataSet.DataType.DATE, "fieldTitle" : "컬럼2" } }
4534     * @author 김흥수
4535     * @since 2015-09-01
4536     * @version 1.0
4537	 */
4538	_setColumnsFromDescs : function(columns) {
4539		var columnNames = {};
4540		this._columnNameArray = [];
4541		this._columns = [];
4542		for ( var fieldName in columns) {
4543			var fieldInfo = columns[fieldName];
4544			this._columns.push(new DataSet.DataSetColumn(fieldName,
4545					fieldInfo["fieldType"], fieldInfo["fieldTitle"],
4546					fieldInfo["fieldFormat"], fieldInfo["virtualField"], fieldInfo["fieldLength"], fieldInfo["fieldDisplayFormat"]));
4547			this._columnNameArray.push(fieldName);
4548			columnNames[fieldName] = this._columnNameArray.length - 1;
4549		}
4550		this._columnNames = columnNames;
4551	}
4552};
4553
4554/**
4555 * @class 데이터셑에서 필요한 utility .
4556 * @author Jun.
4557 * @since 2013-03-28
4558 * @version 1.0
4559 */
4560
4561DataSet.Util = {}; // 데이터셑에서 사용할 Util
4562
4563/**
4564 * 데이터 출력혹은 원본을 유지해야 할경우 데이터를 복사함.
4565 *
4566 * @param obj json 객체
4567 * @return clone 된 객체
4568 * @author Jun.
4569 * @since 2013-03-28
4570 * @version 1.0
4571 */
4572DataSet.Util.objectClone = function(obj) {
4573	var clone = {};
4574	var value = null;
4575	var key = null;
4576
4577	for (key in obj) {
4578		value = obj[key];
4579
4580		if (value == null) {
4581			clone[key] = value;
4582		} else if (typeof (value.tagName) == "undefined") {
4583			clone[key] = value;
4584		} else if (typeof value == 'object') {
4585			clone[key] = this.objectClone(value);
4586		} else {
4587			/*
4588			 * if(typeof(encode) != "undefined" && encode) clone[key] =
4589			 * encodeURIComponent( value); else
4590			 */
4591			clone[key] = value;
4592		}
4593	}
4594
4595	return clone; // $.extend(true,{},obj);//
4596};
4597
4598/**
4599 * 객체에 이벤트를 추가함.
4600 *
4601 * @param elm(HTMLElement)
4602 * @param eventNm(String)
4603 * @param handler(function)
4604 * @author Jun.
4605 * @since 2013-03-28
4606 * @version 1.0
4607 */
4608DataSet.Util.addEvent = function(elm, eventNm, handler) {
4609	DataSet.Util.removeEvent(elm, eventNm, handler);
4610
4611	if (elm.addEventListener) {
4612		elm.addEventListener(eventNm, handler);
4613	} else if (elm.attachEvent) {
4614		elm.attachEvent("on" + eventNm, handler);
4615	}
4616};
4617
4618/**
4619 * 객체에 이벤트를 제거함.
4620 *
4621 * @param elm(HTMLElement)
4622 * @param eventNm(String)
4623 * @param handler(function)
4624 * @author Jun.
4625 * @since 2013-03-28
4626 * @version 1.0
4627 */
4628DataSet.Util.removeEvent = function(elm, eventNm, handler) {
4629	if (elm.removeEventListener) {
4630		elm.removeEventListener(eventNm, handler);
4631	} else if (elm.detachEvent) {
4632		elm.detachEvent("on" + eventNm, handler);
4633	}
4634};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.