PageSourceSearch

https://www.step.or.kr/koreatech/js/step.ekt.js;jsessionid=1134C1EB3DD8C0B265F33DCA96D1E47B.tc_181_01?

js step.or.kr collected 2026-09-26 04:23:59 UTC 55,161 bytes, 1,721 lines download raw bytes

1window.StepEkt = window.StepEkt || {};
2
3//$(document).ajaxStart($.blockUI).ajaxStop($.unblockUI);
4
5jQuery.fn.extend({
6	getMaxZ : function() {
7		return Math.max.apply(null, jQuery(this).map(function() {
8			var z;
9			return isNaN(z = parseInt(jQuery(this).css("z-index"), 10)) ? 0 : z;
10		}));
11	},
12	ncsCategoryList: function(options) {
13    const defaultOption = {
14        ncs_data : {},
15        useBlock : "Y"
16    };
17    options = $.extend({}, defaultOption, options || {});
18
19    // 클래스 코드들
20    const classCodes = ['lrgClssCd', 'mddlClssCd', 'smllClssCd', 'mcroClssCd', 'abltyUntClssCd', 'abltyUntFctrClssCd']
21  .map(key => ({ key, value: options[key] }))
22  .filter(item => item.value != null && item.value !== "")  // null이나 빈 문자열이 아닌 경우만 필터
23  .map(item => item.value);
24
25    const $self = $(this);
26    const $parent = $self.parent();
27
28    function makeSelect(lvl, upNcsClssCd) {
29        return new Promise((resolve, reject) => {
30            const data = {
31                p_lvl: lvl,
32                useBlock: options.useBlock,
33                upNcsClssCd: (upNcsClssCd != "") ? upNcsClssCd : null
34            };
35            StepEkt.ajax({
36                url: CP + "/mngs/ekt/selectNcsClssListAjax.do",
37                data: data,
38                success: function(response) {
39                    if (response.list.length > 0) {
40                        const thisVal = classCodes[lvl - 1];
41                        let str = `<div style="float:left; min-width:15%;" ncsDivArea="${lvl}"><select class="selectpicker" ncsSelectArea="${lvl}"><option value="">전체</option>`;
42                        response.list.forEach(function(obj) {
43                            str += `<option value="${obj.ncsClssCd}" ${obj.ncsClssCd == thisVal ? 'selected' : ''}>${obj.cdNm}</option>`;
44                        });
45                        str += `</select></div>`;
46                        const $component = $(str);
47                        $self.append($component);
48
49                        $component.find('select').on('change', function() {
50                            const selectedVal = $(this).val();
51                            $self.find('[ncsDivArea]').each(function() {
52                                if ($(this).attr('ncsDivArea') > lvl) {
53                                    $(this).remove();
54                                }
55                            });
56
57                            if (selectedVal != "") {
58                                processSelect(lvl + 1, selectedVal);
59                            } else {
60                                refreshSelectPickers(lvl);
61                            }
62                        });
63
64                        resolve(lvl);
65                    } else {
66                        resolve(-1);
67                    }
68                },
69                fail: function() {
70                    alert("작업 중 오류가 발생했습니다.");
71                    reject();
72                }
73            });
74        });
75    }
76
77    function refreshSelectPickers(upToLevel) {
78        for (let i = 1; i <= upToLevel; i++) {
79            $self.find(`[ncsSelectArea="${i}"]`).selectpicker('refresh');
80        }
81        $parent.find("[ncsDivArea]").css("display", "inline-block").css("margin-right", "5px");
82        $parent.css("width", $parent.find("[ncsDivArea]").length > 1 ? "100%" : "");
83    }
84
85    function processSelect(lvl = 1, upNcsClssCd = '') {
86        makeSelect(lvl, upNcsClssCd).then(nextLvl => {
87            if (nextLvl > 0 && nextLvl < classCodes.length) {
88                processSelect(nextLvl + 1, classCodes[nextLvl - 1]);
89            } else {
90                refreshSelectPickers(lvl);
91            }
92        }).catch(() => {
93            console.log('An error occurred');
94        });
95    }
96
97    processSelect();
98	},
99	ncsCategoryListReg : function(options) {
100		const defaultOption = {
101			ncs_data : {},
102			useBlock : "Y"
103		};
104		options = $.extend({}, defaultOption, options || {});
105		//console.table(options);
106
107		const lrgClssCd = options.lrgClssCd;
108		const mddlClssCd = options.mddlClssCd;
109		const smllClssCd = options.smllClssCd;
110		const mcroClssCd = options.mcroClssCd;
111		const abltyUntClssCd = options.abltyUntClssCd;
112		const abltyUntFctrClssCd = options.abltyUntFctrClssCd;
113
114		const $self = $(this);
115		const $parent = $self.parent();
116
117		function makeSelect(lvl, upNcsClssCd) {
118			const data = {
119				p_lvl : lvl,
120				useBlock : options.useBlock,
121				upNcsClssCd : (upNcsClssCd != "") ? upNcsClssCd : null
122			};
123			StepEkt.ajax({
124				url : CP + "/mngs/ekt/selectNcsClssListAjax.do",
125				data: data,
126				success: function(response) {
127					if (response.list.length > 0) {
128						let thisVal, nextVal;
129						if (lvl == 1) {
130							thisVal = lrgClssCd;
131							nextVal = mddlClssCd;
132						} else if (lvl == 2)  {
133							thisVal = mddlClssCd;
134							nextVal = smllClssCd;
135						} else if (lvl == 3)  {
136							thisVal = smllClssCd;
137							nextVal = mcroClssCd;
138						} else if (lvl == 4)  {
139							thisVal = mcroClssCd;
140							nextVal = abltyUntClssCd;
141						} else if (lvl == 5)  {
142							thisVal = abltyUntClssCd;
143							nextVal = abltyUntFctrClssCd;
144						} else if (lvl == 6)  {
145							thisVal = abltyUntFctrClssCd;
146							nextVal = '';
147						}
148
149						let str = `<div style="float:left; min-width:15%;" ncsDivArea="` + lvl + `"><select class="selectpicker" ncsSelectArea="` + lvl + `"><option value="">전체</option>`;
150						response.list.forEach(function(obj, idx) { str += `<option value="` + obj.ncsClssCd + `" `; if (obj.ncsClssCd == thisVal) { str += `selected` }; str += `>` + obj.cdNm + `</option>`;});
151						str += `</select></div>`;
152						
153						const $component = $(str);
154						$component.find("select").on("change", function() {
155							$self.find("[ncsDivArea]").each(function(idx, obj) {
156								if ($(obj).attr("ncsDivArea") > lvl) {
157									$(obj).remove();
158								}
159							});
160							const $self2 = $(this);
161							const value = $self2.val();
162							if (value != "") {
163								makeSelect(lvl + 1, value);
164							}
165							$parent.css("width", $parent.find("[ncsDivArea]").length > 1 ? "100%" : "");
166
167							$parent.find("[ncsDivArea]").css("display", "inline-block").css("margin-right", "5px");
168						});
169						$self.append($component);
170						$self.find("[ncsSelectArea="+ lvl +"]").selectpicker('refresh');
171						$parent.css("width", $parent.find("[ncsDivArea]").length > 1 ? "100%" : "");
172						$parent.find("[ncsDivArea]").css("display", "inline-block").css("margin-right", "5px");
173
174						if (nextVal != undefined && nextVal != '') {
175							makeSelect(lvl + 1, thisVal);
176						}
177					}
178				},
179				fail: function(result, data) {
180					alert("작업 중 오류가 발생했습니다.");
181				}
182			});
183		}
184		makeSelect(1);
185	},
186	ncsCategoryListReset : function(options) {
187		var $self = $(this);
188		var $parent = $self.parent();
189		[6, 5, 4, 3, 2].forEach(function(obj, idx) {
190			$self.find("[ncsDivArea=" + obj + "]").remove();
191		});
192		$self.find("[ncsDivArea=1]").find('option:first').prop('selected', true);
193		$self.find("[ncsDivArea=1]").selectpicker('refresh');
194
195		$self.find("[ncsSelectArea=1]").find('option:first').prop('selected', true);
196		$self.find("[ncsSelectArea=1]").selectpicker('refresh');
197		$parent.css("width", $parent.find("[ncsDivArea]").length > 1 ? "100%" : "");
198
199		$parent.find("[ncsDivArea]").css("display", "inline-block").css("margin-right", "5px");
200	},
201	ncsSelectValue : function(lvl) {
202		var $self = $(this);
203		var $parent = $self.parent();
204		var value = "";
205		if ($self.find("[ncsSelectArea=" + lvl + "] option:selected").length > 0) {
206			value = $self.find("[ncsSelectArea=" + lvl + "] option:selected").val();
207		}
208		return value;
209	}
210});
211
212(function($) {
213	$.each(['show', 'hide'], function(i, ev) {
214		var el = $.fn[ev];
215		$.fn[ev] = function() {
216			var oldVisble = $(this).is(':visible');
217			var ret = el.apply(this, arguments);
218			if (oldVisble != $(this).is(':visible')) this.trigger(ev);
219			return ret;
220		};
221	});
222})(jQuery);
223
224StepEkt.nvl = function(value, defaultValue) {
225	if (value == null || value == undefined || value == '') {
226		return defaultValue;
227	}
228	return value;
229}
230
231StepEkt.random = function(str) {
232	return str + "_" + new Date().getTime() + "_" + parseInt(Math.random() * 1000000000);
233};
234
235StepEkt.dateToStr = function(timestamp) {
236	var date = new Date(timestamp);
237    return date.getFullYear() + `년 ` + (date.getMonth() + 1) + `월 ` + date.getDate() + `일`;
238};
239
240StepEkt.currenty = function(money) {
241	try {
242		return money.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
243
244		/*
245		var formatter = new Intl.NumberFormat('ko-KR', {
246			style: 'currency',
247			currency: 'KRW',
248			// These options are needed to round to whole numbers if that's what you want.
249			//minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
250			//maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
251		});
252
253		return formatter.format(money);
254		*/
255	} catch (e) {
256		return money;
257	}
258};
259
260StepEkt.prettySec = function(value) {
261	var hour = parseInt(value / 3600);
262	var min = parseInt((value % 3600) / 60);
263	var sec = value % 60;
264
265	if (hour > 0) {
266		return hour + "시 " + min + "분 " + sec + "초";
267	} else if (min > 0) {
268		return min + "분 " + sec + "초";
269	}
270	return sec + "초";
271};
272
273StepEkt.arraySortByKey = function(array, key) {
274	return array.sort(function(a, b) {
275		var x = a[key];
276		var y = b[key];
277		return ((x < y) ? -1 : ((x > y) ? 1 : 0));
278	});
279};
280
281StepEkt.existsList = function(src, list) {
282	var result = false;
283	$.each(list, function(idx, obj) {
284		if (src == obj) {
285			result = true;
286			return false;
287		}
288	});
289	return result;
290};
291
292StepEkt.imagePreview = function(options) {
293	var file = options.file;
294	var image = options.image;
295	if (image.attr("src") == undefined || image.attr("src") == "") {
296		image.hide();
297	}
298	image.on("error", function() {
299		image.hide();
300	});
301	file.change(function() {
302		var files = this.files;
303		if (files && files[0]) {
304			var reader = new FileReader();
305			reader.onload = function(e) {
306				image.attr("src", e.target.result);
307				image.show();
308			}
309			reader.readAsDataURL(files[0]);
310		}
311	});
312};
313
314StepEkt.emailList = function(options) {
315	var list = options.list;
316	var directName = options.directName;
317	var listPlace = options.listPlace;
318	var targetPlace = options.targetPlace;
319	listPlace.empty();
320	$.each(list, function(idx, obj) {
321		var option = $("<option></option>").attr("value", obj).text(obj);
322		listPlace.append(option);
323	});
324	(function() {
325		var option = $("<option></option>").attr("value", "").text(directName);
326		listPlace.append(option);
327	})();
328	listPlace.on("change", function() {
329		var value = listPlace.find("option:selected").val();
330		if (value == "") {
331			targetPlace.removeAttr("disabled");
332		} else {
333			targetPlace.attr("disabled", true);
334		}
335		targetPlace.val(value);
336	});
337	listPlace.trigger("change");
338};
339
340StepEkt.scrollOn = function() {
341	//var scrollTop = parseInt($('html').css('top'));
342	$('html').removeClass('noscroll');
343	//$('html,body').scrollTop(-scrollTop);
344	if (window.stepEktScrollTop != null) {
345		$('html,body').scrollTop(-window.stepEktScrollTop);
346		console.log('scrollOn', 'window.stepEktScrollTop', window.stepEktScrollTop);
347	}
348};
349
350StepEkt.scrollOff = function() {
351	if ($(document).height() > $(window).height()) {
352		var stepEktScrollTop = ($('html').scrollTop()) ? $('html').scrollTop() : $('body').scrollTop();
353		//$('html').addClass('noscroll').css('top', -stepEktScrollTop);
354		window.stepEktScrollTop = stepEktScrollTop;
355		console.log('scrollOff', 'window.stepEktScrollTop', window.stepEktScrollTop);
356	}
357};
358
359StepEkt.blockUI = function() {
360	StepEkt.isBlock = StepEkt.isBlock || false;
361	if (! StepEkt.isBlock) {
362		StepEkt.isBlock = true;
363		StepEkt.scrollOff();
364	}
365	parent.$.blockUI.defaults.message = `<img src='` + CP + `/koreatech/asset/image/loading.gif'/>`;
366	//$.blockUI({ baseZ : $("body *").getMaxZ() });
367	parent.$.blockUI({
368        //baseZ: $("body *").getMaxZ(),
369        baseZ: 99999,
370        css: {
371            border: 'none', // 테두리 없음
372            backgroundColor: 'transparent' // 배경색 없음
373        }
374    });
375};
376
377StepEkt.unblockUI = function() {
378	StepEkt.isBlock = StepEkt.isBlock || false;
379	if (StepEkt.isBlock) {
380		StepEkt.isBlock = false;
381		StepEkt.scrollOn();
382	}
383	parent.$.unblockUI();
384};
385
386StepEkt.ajax = function(options) {
387	var defaultOption = {
388		useBlock: "Y",
389		method: "GET",
390		dataType: "json",
391		async: true,
392		success: function() {},
393		fail: function() { alert("작업 중 오류가 발생했습니다."); },
394		complete: function() {}
395	};
396	options = $.extend({}, defaultOption, options || {});
397	if (options.useBlock == "Y") {
398		StepEkt.blockUI();
399	}
400	var data = options.data;
401	if (data == undefined) {
402		data = {};
403	} else {
404		if (data instanceof jQuery) {
405			data = data.get(0)
406		}
407		if (data.nodeName == "FORM") {
408			data = new FormData(data);
409		}
410	}
411	var ajaxData = {
412		url: options.url,
413		data: data,
414		type: options.method,
415		async: options.async
416	};
417	if (options.dataType != null) {
418		ajaxData.dataType = options.dataType; // return type
419	}
420	if (data instanceof FormData) {
421		ajaxData.contentType = false;
422		ajaxData.processData = false;
423	}
424
425//	console.log('options.contentType:'+options.contentType);
426	///*
427	if(options.contentType != null){
428		ajaxData.contentType = options.contentType;
429	}
430	//*/
431	$.ajax(ajaxData).done(function(response) {
432		if (options.useBlock == "Y") {
433			StepEkt.unblockUI();
434		}
435		//console.log(response);
436		var result = response.result;
437		var data = response;
438
439		if (result == 0) {
440			options.success(data);
441		} else if (result == -1) {
442			alert("로그인 상태가 아닙니다.");
443			location.href = CP + "/login/login.do";
444		} else if (result == -2) {
445			alert("사용권한이 없습니다.");
446			location.href = CP + "/";
447		} else if (result == -3) { // binding error
448			options.fail(result, data);
449		} else {
450			options.fail(result, data);
451		}
452	}).fail(function(response) {
453		if (options.useBlock == "Y") {
454			StepEkt.unblockUI();
455		}
456		alert("작업 중 오류가 발생했습니다.");
457	}).always(function(response) {
458		options.complete(response);
459	});
460};
461
462StepEkt.dext = {
463	ready : function(dextEditorId, newFunc) {
464		var oldFunc = window.dext_editor_loaded_event;
465		window.dext_editor_loaded_event = function(editor) {
466			if (editor.ID == dextEditorId) {
467				//DEXT5.util.getEditorByName(dextEditorId);
468				setTimeout(newFunc, 0);
469			}
470
471			if (oldFunc != null && oldFunc != undefined) {
472				oldFunc(editor);
473			}
474		}
475	}
476};
477
478StepEkt.viewer = {
479	_createDextObj : function(dextEditorId) {
480		return {
481			getId : function() {
482				return dextEditorId;
483			},
484			getHtmlValue : function() {
485				return DEXT5.getHtmlValue(dextEditorId);
486			},
487			getTextValue : function() {
488				return DEXT5.getBodyTextValue(dextEditorId);
489			},
490			setHtmlValue : function(value) {
491				return DEXT5.setHtmlContents(value, dextEditorId);
492			},
493			setTextValue : function() {
494				return DEXT5.setBodyTextContents(value, dextEditorId);
495			}
496		};
497	},
498	find : function(options) {
499		defaultOption = {
500			placeHolder: ""
501		};
502		options = $.extend({}, defaultOption, options || {});
503		var dextEditorId = options.placeHolder.attr("dextEditorId");
504		return this._createDextObj(dextEditorId);
505	},
506	create : function(options) {
507		defaultOption = {
508			placeHolder: "",
509			width: "100%",
510			height: "100%",
511			ready: null
512		};
513		options = $.extend({}, defaultOption, options || {});
514		var dextEditorId = StepEkt.random("deId");
515		var placeHolder = options.placeHolder;
516		if (placeHolder.length == 0) {
517			console.error("placeHolder error");
518			return {};
519		}
520		var placeHolderId = placeHolder.attr("id");
521		placeHolder.attr("dextEditorId", dextEditorId);
522		if (placeHolderId == undefined || placeHolderId == "") {
523			placeHolderId = StepEkt.random("deId");
524			placeHolder.attr("id", placeHolderId);
525		}
526		if (options.ready != null) {
527			StepEkt.dext.ready(dextEditorId, options.ready);
528		}
529		DEXT5.config.EditorHolder = placeHolderId;
530		DEXT5.config.Width = options.width;
531		DEXT5.config.Height = options.height;
532        DEXT5.config.Mode = "view";
533        DEXT5.config.HandlerUrl = location.origin + CP + "/editor/dext5editorHandler.do";
534        // 뷰어도 편집영역과 동일한 서식으로 맞춤
535        DEXT5.config.userCssUrl = location.origin + CP + "/step/css/editor_content.css";
536		new Dext5editor(dextEditorId);
537		return this._createDextObj(dextEditorId);
538	}
539};
540
541StepEkt.editor = {
542	_createDextObj : function(dextEditorId) {
543		return {
544			getId : function() {
545				return dextEditorId;
546			},
547			getHtmlValue : function() {
548				return DEXT5.getHtmlValue(dextEditorId);
549			},
550			getBodyValue : function() {
551				return DEXT5.getBodyValue(dextEditorId);
552			},
553			getTextValue : function() {
554				return DEXT5.getBodyTextValue(dextEditorId);
555			},
556			setHtmlValue : function(value) {
557				return DEXT5.setHtmlContents(value, dextEditorId);
558			},
559			setBodyValue : function(value) {
560				return DEXT5.setBodyValue(value, dextEditorId);
561			},
562			setTextValue : function(value) {
563				if (value == null) {
564					value = "";
565				} else {
566					value = value.replace(/(?:\r\n|\r|\n)/g, '<br />');
567				}
568				return DEXT5.setBodyValue(value, dextEditorId);
569			}
570		};
571	},
572	find : function(options) {
573		defaultOption = {
574			placeHolder: ""
575		};
576		options = $.extend({}, defaultOption, options || {});
577		var dextEditorId = options.placeHolder.attr("dextEditorId");
578		return this._createDextObj(dextEditorId);
579	},
580	create : function(options) {
581		defaultOption = {
582			placeHolder: "",
583			width: "100%",
584			height: "100%",
585			ready: null,
586			dialogWindow: window
587		};
588		options = $.extend({}, defaultOption, options || {});
589		var maxZ = $("body *").getMaxZ();
590		var dextEditorId = StepEkt.random("deId");
591		var placeHolder = options.placeHolder;
592		if (placeHolder.length == 0) {
593			console.error("placeHolder error");
594			return {};
595		}
596		var placeHolderId = placeHolder.attr("id");
597		placeHolder.attr("dextEditorId", dextEditorId);
598		if (placeHolderId == undefined || placeHolderId == "") {
599			placeHolderId = StepEkt.random("dehId");
600			placeHolder.attr("id", placeHolderId);
601		}
602
603		if (options.ready != null) {
604			StepEkt.dext.ready(dextEditorId, options.ready);
605		}
606		DEXT5.config.EditorHolder = placeHolderId;
607		DEXT5.config.Width = options.width;
608		DEXT5.config.Height = options.height;
609        DEXT5.config.Mode = "edit";
610		DEXT5.config.DialogWindow = options.dialogWindow;
611        DEXT5.config.HandlerUrl = location.origin + CP + "/editor/dext5editorHandler.do";
612        // 편집 영역을 보기 화면(.b_content)과 동일한 서식으로 맞춤
613        DEXT5.config.userCssUrl = location.origin + CP + "/step/css/editor_content.css";
614		new Dext5editor(dextEditorId);
615		return this._createDextObj(dextEditorId);
616	}
617};
618
619StepEkt.uploader = {
620	create : function(options) {
621		defaultOption = {
622			width: "100%",
623			height: "100%"
624		};
625		options = $.extend({}, defaultOption, options || {});
626		var maxZ = $("body *").getMaxZ();
627		var dextUploaderName = StepEkt.random("duId");
628		var placeHolder = options.placeHolder;
629		if (placeHolder.length == 0) {
630			console.error("placeHolder error");
631			return {};
632		}
633		var placeHolderId = placeHolder.attr("id");
634		if (placeHolderId == undefined || placeHolderId == "") {
635			placeHolderId = StepEkt.random("duhId");
636			placeHolder.attr("id", placeHolderId);
637		}
638        DEXT5UPLOAD.config.Width = options.width;
639        DEXT5UPLOAD.config.Height = options.height;
640        DEXT5UPLOAD.config.UseFileSort = '0';
641        DEXT5.config.HandlerUrl = location.origin + CP + "/editor/dext5editorHandler.do";
642		new Dext5Upload(dextUploaderName);
643		var retObj = {
644		};
645		return retObj;
646	}
647};
648
649StepGrid = {
650	create : function(options, isChangeEvent, isClickEvent) {
651		defaultOption = {
652			gridId: StepEkt.random("grid"),
653			popupHolder: "",
654			width: "100%",
655			height: "100%",
656			rowHeight : "",
657			ready: function() {},
658			scroll: function() {},
659			lblFunctions: {},
660			events: [],
661			footer: "",
662			editable: false,
663			doubleClickEnabled: false,
664			filterable: false
665		};
666
667		defaultColumn = {
668			type: "DataGridColumn",
669			headerText:""
670		};
671
672		var extOptions = $.extend({}, defaultOption, options || {});
673
674		function getLayoutStr(options) {
675			var layoutStr = ``;
676
677			if (options.layout != null) {
678				layoutStr = `<?xml version="1.0" encoding="utf-8"?><rMateGrid>`;
679
680				if (options.layout.options != null) {
681					options.layout.options.forEach(function(option) {
682						var str = `<` + option.type;
683						for (var key in option) {
684							if (key == "type") {
685							} else {
686								str += ` ` + key + `="` + option[key] + `"`;
687							}
688						}
689						str += `/>`;
690						layoutStr += str;
691					});
692				}
693
694				var lockStr = ``;
695
696				if (options.lock_row != null && options.lock_row != "") {
697					lockStr += ` lockedRowCount="` + options.lock_row + `" `;
698				}
699				if (options.lock_col != null && options.lock_col != "") {
700					lockStr += ` lockedColumnCount="` + options.lock_col + `" `;
701				}
702
703				layoutStr += `<NumberFormatter id="numfmt" useThousandsSeparator="true"/>`;
704				layoutStr += `<DateFormatter id="datefmt" formatString="YYYY.MM.DD"/>`;
705				layoutStr += `<PercentFormatter id="percfmt" useThousandsSeparator="true"/>`;
706
707				//DataGrid 레이아웃 설정 시작
708				layoutStr += `<DataGrid id="dg1" `+lockStr+`headerColors="[#F9F9FB,#F9F9FB]" verticalAlign="middle" textAlign="center"`;
709
710				//행높이 설정시 DataGrid의 마지막에 행높이 추가
711				if(!isEmpty(options.rowHeight)) {
712					let rowHeight = options.rowHeight;
713					//레이아웃 추가
714					appendLayout("rowHeight", rowHeight);
715				}
716
717				//선택모드 설정 (multipleCells, multipleRows, none, singleCell, singleRow중 택1)
718				if(!isEmpty(options.selectorControl)) {
719					let selectionMode = options.selectorControl;
720					if(selectionMode != "multipleCells" && selectionMode != "multipleRows" && selectionMode != "none"
721						&& selectionMode != "singleCell" && selectionMode != "singleRow") {
722						selectionMode = "singleRow"; //기본값 설정
723					}
724					//레이아웃 추가
725					appendLayout("selectionMode", selectionMode);
726				}
727
728				//컬럼 정렬가능여부 조정 (true,false중 택일, 기본 false)
729				if(!isEmpty(options.sortableColumns)) {
730					let sortableColumns = options.sortableColumns;
731					if(sortableColumns != "true" && sortableColumns != "false") {
732						sortableColumns = "false";
733					}
734					//레이아웃 추가
735					appendLayout("sortableColumns", sortableColumns);
736				}
737
738				//수평스크롤 옵션 유효성 체크 (auto, on, off)
739				if(!isEmpty(options.horizontalScrollPolicy)) {
740					let horizontalScrollPolicy = options.horizontalScrollPolicy;
741					if(horizontalScrollPolicy != "auto" && horizontalScrollPolicy != "on" && horizontalScrollPolicy != "off") {
742						horizontalScrollPolicy = "auto";
743					}
744					//레이아웃 추가
745					appendLayout("horizontalScrollPolicy", horizontalScrollPolicy);
746				}
747
748				//수정모드 지정 (true,false중 택일, 기본 false)
749				if(!isEmpty(options.editable)) {
750					let editable = options.editable;
751					if(editable != "true" && editable != "false") {
752						editable = "false";
753					}
754					//레이아웃 추가
755					appendLayout("editable", editable);
756				}
757
758				//더블클릭 가능 여부 (true,false중 택일, 기본 false, true의 경우 더블클릭하면 해당 셀을 수정할수 있게 됩니다)
759				if(!isEmpty(options.doubleClickEnabled)) {
760					let doubleClickEnabled = options.doubleClickEnabled;
761					if(doubleClickEnabled != "true" && doubleClickEnabled != "false") {
762						doubleClickEnabled = "false";
763					}
764					//레이아웃 추가
765					appendLayout("doubleClickEnabled", doubleClickEnabled);
766
767				}
768
769				layoutStr += `>`;
770				//DataGrid 레이아웃 설정 끝
771				if (options.layout.columns != null) {
772					layoutStr += `<columns>`;
773					options.layout.columns.forEach(function(column) {
774						column = $.extend({}, defaultColumn, column);
775						processColumn(column);
776					});
777					layoutStr += `</columns>`;
778				} else if (options.layout.groupColumns != null) {
779					layoutStr += `<groupedColumns>`;
780					options.layout.groupColumns.forEach(function (column) {
781						column = $.extend({}, defaultColumn, column);
782						processColumn(column);
783					});
784					layoutStr += `</groupedColumns>`;
785				}
786
787				// footer 설정
788				if (options.footer == "footer_smsEmlUseStatusList"){
789					// SMS/EML 사용 현황
790					layoutStr += `<footers>`;
791					layoutStr += `<DataGridFooter height="35">`;
792					layoutStr += `<DataGridFooterColumn label="합계" colSpan = "5" textAlign="center"/>`;
793					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{smsCnt}" formatter="{numfmt}" textAlign="right"/>`;
794					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{emlCnt}" formatter="{numfmt}" textAlign="right"/>`;
795					layoutStr += `</DataGridFooter>`;
796					layoutStr += `</footers>`;
797				} else if (options.footer == "footer_companyDealingStateMain"){
798					// 업채별 매매현황
799					layoutStr += `<footers>`;
800					layoutStr += `<DataGridFooter height="35">`;
801					layoutStr += `<DataGridFooterColumn label="합계" colSpan = "3" textAlign="center"/>`;
802					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{okCnt}" formatter="{numfmt}" textAlign="right"/>`;
803					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{cancelCnt}" formatter="{numfmt}" textAlign="right"/>`;
804					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{sellCnt}" formatter="{numfmt}" textAlign="right"/>`;
805					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{rejectCnt}" formatter="{numfmt}" textAlign="right"/>`;
806					layoutStr += `</DataGridFooter>`;
807					layoutStr += `</footers>`;
808				} else if (options.footer == "footer_profitStatus"){
809					// 과정별 매출현황
810					layoutStr += `<footers>`;
811					layoutStr += `<DataGridFooter height="35">`;
812					layoutStr += `<DataGridFooterColumn label="합계" colSpan = "7" textAlign="center"/>`;
813					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{prchsAmt}" formatter="{numfmt}" textAlign="right"/>`;
814					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{rfndAmt}" formatter="{numfmt}" textAlign="right"/>`;
815					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{prftAmt}" formatter="{numfmt}" textAlign="right"/>`;
816					layoutStr += `</DataGridFooter>`;
817					layoutStr += `</footers>`;
818				} else if (options.footer == "footer_saleStatusByCourse"){
819					// 과정별 판매현황
820					layoutStr += `<footers>`;
821					layoutStr += `<DataGridFooter height="35">`;
822					layoutStr += `<DataGridFooterColumn label="합계" colSpan = "11" textAlign="center"/>`;
823					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{prchsCnt}" formatter="{numfmt}" textAlign="right"/>`;
824					layoutStr += `<DataGridFooterColumn summaryOperation="SUM" dataColumn="{rfndCnt}" formatter="{numfmt}" textAlign="right"/>`;
825					layoutStr += `</DataGridFooter>`;
826					layoutStr += `</footers>`;
827				}
828
829				//레이아웃 추가하는 함수
830				function appendLayout(optionName, option) {
831					layoutStr += ` ` + optionName + `="` + option + `"`
832				}
833
834				function getType(column) {
835					var type = column.type;
836					if (type == "group") {
837						return "DataGridColumnGroup";
838					} else if (type == "select") {
839						return "DataGridSelectorColumn";
840					}
841					return type;
842				}
843				function processColumn(column) {
844					layoutStr += `<` + getType(column);
845					var group = [];
846					for (var key in column) {
847						var value = column[key];
848						if (key == "type") {
849						} else if (key == "group") {
850							group = value;
851						} else if (key == "labelJsFunction") {
852							layoutStr += ` ` + key + `="` + options.gridId + value + `"`;
853						} else if (key == "visible") {
854							layoutStr += ` ` + key + `="` + value + `"`;
855						} else if (key == "headerText") {
856							layoutStr += ` ` + key + `="` + value.replaceAll("<", "&lt;").replaceAll(">", "&gt;") + `"`;
857						} else {
858							layoutStr += ` ` + key + `="` + value + `"`;
859						}
860					}
861					if ((options.filterable && (isEmpty(column.popfilterable) || column.popfilterable)) == true ) {
862						layoutStr += ` filterable="true"  filterType="list" `;
863					} else {
864						layoutStr += ` filterable="false" `;
865					}
866					layoutStr += `>`;
867
868					$.each(group, function (idx, column) {
869						column = $.extend({}, defaultColumn, column);
870						processColumn(column);
871					});
872					layoutStr += `</` + getType(column) + `>`;
873				}
874				layoutStr += `</DataGrid>`;
875				layoutStr += `<Style>`;
876				layoutStr += `.makeCellAsLink{`;
877				layoutStr += `text-decoration: underline;`
878				layoutStr += `color:#0000ff;cursor:hand;`
879				layoutStr += `font-weight:bold;`
880				layoutStr += `}`;
881				layoutStr += `</Style>`;
882				layoutStr += `<Box id="messageBox" width="100%" height="100%" backgroundAlpha="0.3" backgroundColor="#CCCCCC" verticalAlign="middle" horizontalAlign="center" visible="false">`;
883				layoutStr += `<Label id="messageLabel" text="" fontSize="18px" fontWeight="bold" color="#666" textAlign="center"/>`;
884				layoutStr += `</Box>`;
885				layoutStr += `</rMateGrid>`;
886			}
887//			console.log(layoutStr);
888			return layoutStr;
889		}
890
891		if (extOptions.popupHolder != null && extOptions.popupHolder != "") {
892			extOptions.popupHolder.css("cursor", "pointer").click(function(evt) {
893				evt.preventDefault();
894				$("[areaGridPopupManage]").remove();
895				let posTop = extOptions.popupHolder.offset().top;
896				let fixedTop = posTop - 250;
897
898
899				let popupGridApp;  // 그리드를 포함하는 div 객체
900    			let popupGridRoot;   // 데이터와 그리드를 포함하는 객체
901				let popupDataGrid;	//실제 그리드를 표시하는 컴포넌트
902
903				let searchedText;
904
905				//그리드객체들 로딩
906				loadGridObject();
907
908				function loadGridObject() {
909					popupGridApp = document.getElementById(extOptions.gridId);  // 그리드를 포함하는 div 객체
910	    			popupGridRoot = popupGridApp.getRoot();   // 데이터와 그리드를 포함하는 객체
911					popupDataGrid = popupGridRoot.getDataGrid();	//실제 그리드를 표시하는 컴포넌트
912				}
913
914				//필터내에서 셀렉션 모드 변경했을경우 필터닫았을때 원래대로 되돌리기 위한 변수
915				let oldSelectionMode = popupDataGrid.getSelectionMode();
916
917				if ( fixedTop < 0 ) fixedTop = 0;
918				var popupStr =
919					`<div class="master_title" style="top:`+fixedTop+`px; left:300px; width:350px !important" areaGridPopupManage>
920						<div class="filter_layer">
921							<button type="button" class="filter_close" btnClose>
922								<img src="` + CP + `/koreatech/asset/img/filter_close.png">
923							</button>
924							<ul>
925								<li>
926									<span>보기</span>
927									<select class="selectpicker" m_count></select>
928								</li>
929								<li>
930									<span>찾기</span>
931									<input type="text" class="normal_input" m_search_text>
932									<div class="filter_search">
933										<button class="btn bg01" btn_prev>이전</button>
934										<button class="btn bg05" btn_next>다음</button>
935									</div>
936								</li>
937							</ul>
938							<div class="filter_btns">
939								<button type="button" btn_filter="Y"><img src="` + CP + `/koreatech/asset/popup/img/common/master_ico1.png" class="mr_5">필터</button>
940								<div>
941									<button type="button" btn_col_lock><img src="` + CP + `/koreatech/asset/popup/img/common/master_ico4.png" class="mr_5">열고정</button>
942									<div class="filter_select">
943										<select class="selectpicker" m_col_count></select>
944									</div>
945								</div>
946								<button type="button" btn_filter="N"><img src="` + CP + `/koreatech/asset/popup/img/common/master_ico2.png" class="mr_5">필터 취소</button>
947								<div>
948									<button type="button" btn_row_lock><img src="` + CP + `/koreatech/asset/popup/img/common/master_ico5.png" class="mr_5">행고정</button>
949									<div class="filter_select">
950										<select class="selectpicker" m_row_count></select>
951									</div>
952								</div>
953								<button type="button" btn_col_hide="Y"><img src="` + CP + `/koreatech/asset/popup/img/common/master_ico3.png" class="mr_5">컬럼 숨기기</button>
954							</div>
955							<div class="filter_colums" areaColumn></div>
956						</div>
957					</div>`;
958				var $popup = $(popupStr);
959				$("body").append($popup);
960				[10, 20, 50, 100].forEach(function(obj) {
961					$popup.find("[m_count]").append(`<option value="` + obj + `" ` + (options.pageUnit == obj ? `selected="selected"` : ``) + `>` + obj + `개</option>`);
962				});
963				popupDataGrid.getColumns().forEach(function(obj, idx) {
964					var column = obj;
965					if (idx == 0) {
966						$popup.find("[m_col_count]").append(`<option value="0">해제</option>`);
967					}
968					if (column.className == "DataGridColumn") {
969						var headerText = column._headerText;
970						var option = $(`<option value="` + (idx + 1) + `"></option>`);
971						option.attr("title", headerText);
972						function getSize(str) {
973							var size = 0;
974							for (var i = 0; i < str.length; i++) {
975								var length = escape(str.charAt(i)).length;
976								if (length > 4) {
977									size++;
978								}
979								size++;
980							}
981							return size;
982						}
983						if (getSize(headerText) > 8) {
984							headerText = headerText.substring(0, 3) + "...";
985						}
986						option.text(headerText);
987						$popup.find("[m_col_count]").append(option);
988					}
989				});
990				[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].forEach(function(obj, idx) {
991					if (idx == 0) {
992						$popup.find("[m_row_count]").append(`<option value="0">해제</option>`);
993					}
994					$popup.find("[m_row_count]").append(`<option value="` + obj + `">` + obj + `</option>`);
995				});
996
997				//컬럼 숨기기 그리기
998				columnHideFunc();
999
1000
1001				//컬럼 숨기기 항목 그리는 함수
1002				function columnHideFunc() {
1003					$popup.find("[areaColumn]").empty();
1004					loadGridObject();
1005					popupDataGrid.getColumns().forEach(function(obj, idx) {
1006						var column = obj;
1007						if (column.className == "DataGridColumn" && !isEmpty(column._headerText)) {
1008							var headerText = column._headerText;
1009							var $columnInfo = $(`<label class="checkbox"><input type="checkbox"><i></i><span></span>` + headerText + `</label>`);
1010							$columnInfo.attr("title", headerText);
1011							if (~-encodeURI(headerText).split(/%..|./).length > 19) {}
1012
1013							//체크박스 이벤트 등록
1014							$columnInfo.find("input[type=checkbox]").prop("checked", column._visible).attr("idx", idx).change(function() {
1015								var self = this;
1016								//이벤트가 동작할때는 popupDataGrid를 다시 불러와서 처리(다른 기능으로 layout이 변경돼서 그리드객체가 바뀔수있음)
1017								popupDataGrid.getColumns()[idx].setVisible(self.checked);
1018							});
1019						}
1020						$popup.find("[areaColumn]").append($columnInfo);
1021					});
1022				}
1023
1024				$popup.find("[btnClose]").click(function(evt) {
1025					evt.preventDefault();
1026					popupDataGrid.setSelectionMode(oldSelectionMode);
1027					$popup.remove();
1028					return false;
1029				});
1030				$popup.find("[m_col_count]").val(dataGrid.getLockedColumnCount());
1031				$popup.find("[m_row_count]").val(dataGrid.getLockedRowCount());
1032				$popup.find("[m_count]").change(function() {
1033					options.pageUnit = $popup.find("[m_count]").val();
1034					extOptions.search();
1035				});
1036
1037				$popup.find("[m_search_text]").on("change", function(evt) {
1038					searchedText = "";
1039				});
1040
1041				$popup.find("[m_search_text]").on("keydown", function(evt) {
1042					if (evt.keyCode == 13) {
1043						let searchVal = $popup.find("[m_search_text]").val();
1044						if (isEmpty(searchVal)) {
1045							alert("검색어를 입력해 주시기 바랍니다.");
1046							return false;
1047						}
1048
1049						//singleCell로 설정할경우 매개변수의 값까지 찾아질수있음
1050//					    popupDataGrid.setSelectionMode('singleCell');
1051						findSearchValue(searchVal);
1052					}
1053				});
1054				$popup.find("[btn_prev]").click(function(evt) {
1055					evt.preventDefault();
1056					var searchVal = $popup.find("[m_search_text]").val();
1057
1058					if(isEmpty(searchVal)){
1059			    		alert("검색어를 입력해 주시기 바랍니다.");
1060						return false;
1061			    	}
1062
1063					if (isEmpty(searchedText)) {
1064						findSearchValue(searchVal);
1065						return;
1066					}
1067
1068					popupGridRoot.searchPrevious();
1069				});
1070				$popup.find("[btn_next]").click(function(evt) {
1071					evt.preventDefault();
1072
1073					var searchVal = $popup.find("[m_search_text]").val();
1074			    	if(searchVal == ""){
1075			    		alert("검색어를 입력해 주시기 바랍니다.");
1076						return false;
1077			    	}
1078
1079					if (isEmpty(searchedText)) {
1080						findSearchValue(searchVal);
1081						return;
1082					}
1083
1084				    popupGridRoot.searchNext();
1085				});
1086
1087				function findSearchValue(value) {
1088					let result = popupGridRoot.search(value);
1089
1090					if (result == true) {
1091						searchedText = value;
1092				    } else {
1093						alert(value+" 을(를) 찾을 수 없습니다");
1094						searchedText = "";
1095					}
1096				}
1097
1098				$popup.find("[btn_filter]").click(function(evt) {
1099					evt.preventDefault();
1100					extOptions.filterable = ($(this).attr("btn_filter") == "Y") ? true : false;
1101					popupGridApp.setLayout(getLayoutStr(extOptions));
1102
1103					//컬럼 숨기기 그리기 setLayout실행시간이 길어서 타이아웃 설정
1104					setTimeout(() => columnHideFunc(), 100);
1105
1106					return false;
1107				});
1108				$popup.find("[btn_col_lock]").click(function(evt) {
1109					evt.preventDefault();
1110					extOptions.lock_col = $popup.find("[m_col_count]").val();
1111					gridApp.setLayout(getLayoutStr(extOptions));
1112
1113					//컬럼 숨기기 그리기 setLayout실행시간이 길어서 타이아웃 설정
1114					setTimeout(() => columnHideFunc(), 100);
1115					return false;
1116				});
1117
1118//				$popup.find("[m_col_count]").click(function(evt) {
1119//					evt.preventDefault();
1120//					extOptions.lock_col = $popup.find("[m_col_count]").val();
1121//					gridApp.setLayout(getLayoutStr(extOptions));
1122//
1123//					//컬럼 숨기기 그리기 setLayout실행시간이 길어서 타이아웃 설정
1124//					setTimeout(() => columnHideFunc(), 100);
1125//					return false;
1126//				});
1127
1128				$popup.find("[m_col_count]").change(function() {
1129					extOptions.lock_col = $popup.find("[m_col_count]").val();
1130					gridApp.setLayout(getLayoutStr(extOptions));
1131
1132					//컬럼 숨기기 그리기 setLayout실행시간이 길어서 타이아웃 설정
1133					setTimeout(() => columnHideFunc(), 100);
1134				});
1135				$popup.find("[m_row_count]").change(function() {
1136					extOptions.lock_row = $popup.find("[m_row_count]").val();
1137					gridApp.setLayout(getLayoutStr(extOptions));
1138
1139					//컬럼 숨기기 그리기 setLayout실행시간이 길어서 타이아웃 설정
1140					setTimeout(() => columnHideFunc(), 100);
1141				});
1142//				$popup.find("[btn_row_lock]").click(function(evt) {
1143//					evt.preventDefault();
1144//					extOptions.lock_row = $popup.find("[m_row_count]").val();
1145//					gridApp.setLayout(getLayoutStr(extOptions));
1146//
1147//					//컬럼 숨기기 그리기 setLayout실행시간이 길어서 타이아웃 설정
1148//					setTimeout(() => columnHideFunc(), 100);
1149//					return false;
1150//				});
1151				$popup.find("[btn_col_hide]").click(function(evt) {
1152					evt.preventDefault();
1153					var status = $popup.find("[btn_col_hide]").attr("btn_col_hide");
1154					if (status == "Y") { // 숨김상태
1155						$popup.find("[btn_col_hide]").attr("btn_col_hide", "N");
1156						$popup.find("[areaColumn]").show();
1157					} else { // 보임상태
1158						$popup.find("[btn_col_hide]").attr("btn_col_hide", "Y");
1159						$popup.find("[areaColumn]").hide();
1160					}
1161					return false;
1162				});
1163				$popup.find(".selectpicker").selectpicker("refresh").on('loaded.bs.select', StepEkt.selectpickerTitle);;
1164				$popup.show();
1165				return false;
1166			});
1167		}
1168
1169		// labelJsFunction 시작
1170		for (var key in extOptions.lblFunctions) {
1171			(function(key) {
1172				var functionName = extOptions.gridId + key;
1173				window[functionName] = extOptions.lblFunctions[key];
1174			})(key);
1175		}
1176		// labelJsFunction 종료
1177
1178		var gridReadyHandlerName = StepEkt.random("gridReadyHandler");
1179		var gridApp = null;
1180		var gridRoot = null;
1181		var dataGrid = null;
1182		var vpos = 0;
1183		var lastVpos = 0;	// 마지막 스크롤 위치
1184		var _isReady = false;
1185		var _isReturn = false;
1186
1187		window[gridReadyHandlerName] = function(id) {
1188			gridApp = document.getElementById(id);  // 그리드를 포함하는 div 객체
1189			gridRoot = gridApp.getRoot();   // 데이터와 그리드를 포함하는 객체
1190
1191			window[gridReadyHandlerName] = null;
1192
1193			gridRoot.addEventListener("layoutComplete", function(event) {
1194				dataGrid = gridRoot.getDataGrid();	// 그리드 객체
1195				dataGrid.addEventListener("scroll", function(event) {
1196					if (event.direction == "vertical") {
1197						vpos = event.position;
1198						if (vpos == 0) {
1199							return;
1200						}
1201						console.log("vpos : "+vpos);
1202						console.log("dataGrid.getMaxVerticalScrollPosition() : "+dataGrid.getMaxVerticalScrollPosition());
1203						if (vpos >= dataGrid.getMaxVerticalScrollPosition()) {
1204							if (vpos != lastVpos) {
1205								lastVpos = vpos;
1206								(function() {
1207									extOptions.scroll();
1208								})();
1209							}
1210						}
1211					}
1212				});
1213				$.each(extOptions.events, function(idx, evtObj) {
1214					if (evtObj.id != null && evtObj.id != "") {
1215						(function() {
1216							var selector = gridRoot.getObjectById(evtObj.id);
1217							selector.addEventListener(evtObj.event, function(evt) {
1218								evtObj.callback(evt, selector);
1219							});
1220						})();
1221					} else {
1222						(function() {
1223							if (evtObj.event == "itemDataChanged") {
1224								gridRoot.addEventListener(evtObj.event, function(evt) {
1225									evtObj.callback(evt);
1226								});
1227							} else {
1228								dataGrid.addEventListener(evtObj.event, function(evt) {
1229									evtObj.callback(evt);
1230								});
1231							}
1232						})();
1233					}
1234				});
1235				dataGrid.setVerticalScrollPosition(vpos);
1236			});
1237			gridRoot.addEventListener("dataComplete", function(event) {
1238				dataGrid = gridRoot.getDataGrid();
1239				if (isChangeEvent) {
1240					dataGrid.addEventListener("change", function(event) {
1241						var rowIndex = event.rowIndex;
1242				        var columnIndex = event.columnIndex;
1243			            var rows = dataGrid.getSelectedIndices();
1244						var rowdata = gridRoot.dataSet[rows];
1245
1246		            	rowSelected(rows, rowdata);
1247					});
1248				}
1249				if (isClickEvent) {
1250					dataGrid.addEventListener("itemClick", function(event) {
1251						event.preventDefault();
1252				    	var rowIndex = event.rowIndex;
1253				        var columnIndex = event.columnIndex;
1254			            var rows = dataGrid.getSelectedIndices();
1255						var rowdata = gridRoot.dataSet[rows];
1256
1257						if (extOptions.itemClicked) {
1258			            	extOptions.itemClicked(rowIndex, columnIndex, rows, rowdata);
1259						} else if (window.itemClicked) {
1260			            	itemClicked(rowIndex, columnIndex, rows, rowdata);
1261						}
1262					});
1263				}
1264				dataGrid.addEventListener("filterClick", function(event) {
1265					var collection = gridRoot.getCollection();
1266					if (collection._localIndex.length > 0) {
1267						retObj.hideNoDataMessage();
1268					} else {
1269						retObj.showNoDataMessage();
1270					}
1271				});
1272			});
1273
1274			gridApp.setLayout(getLayoutStr(extOptions));
1275
1276			_isReady = true;
1277
1278			function _ready() {
1279				if (_isReturn) {
1280					extOptions.ready();
1281				} else {
1282					setTimeout(_ready, 100);
1283				}
1284			}
1285
1286			setTimeout(_ready, 0);
1287		}
1288
1289		rMateGridH5.create(extOptions.gridId, extOptions.parentId, "rMateOnLoadCallFunction=" + gridReadyHandlerName, extOptions.width, extOptions.height);
1290
1291		var retObj = {
1292			gridId : extOptions.gridId,
1293			isReady : function() {
1294				return _isReady;
1295			},
1296			setData : function(data) {
1297				vpos = 0;
1298				lastVpos = 0;
1299				this.hideNoDataMessage();
1300				gridApp.setData(data);
1301			},
1302			addData : function(data) {
1303				gridApp.addData(data);
1304			},
1305			getSelectedCheck : function(selectorId) {
1306				try {
1307					var selectorColumn = gridRoot.getObjectById(selectorId);
1308					var indices = selectorColumn.getSelectedIndices();
1309					var collection = gridRoot.getCollection();
1310					var sData = collection.getSource();
1311					var list = [];
1312					indices.forEach(function(index) {
1313						list.push(sData[index]);
1314					});
1315					return list;
1316				} catch {
1317					return[];
1318				}
1319			},
1320			getSelectedIndex : function() {
1321				return dataGrid.getSelectedIndex();
1322			},
1323			setSelectedIndex : function(num) {
1324				dataGrid.setSelectedIndex(num);
1325			},
1326			getSelectedItem : function() {
1327				return dataGrid.getSelectedItem();
1328			},
1329			getSelectedItemsIndices : function() {
1330				return dataGrid.getSelectedIndices();
1331			},
1332			getSelectedItemsData : function() {
1333				return dataGrid.getSelectedItems();
1334			},
1335			removeItemAt : function(index) {
1336				gridRoot.removeItemAt(index);
1337			},
1338			getLength: function() {
1339				return gridRoot.getLength();
1340			},
1341			getSelectedRowId : function(num) {	// 선택된 row의 id 읽기
1342				return gridRoot.dataSet[num].id;
1343			},
1344			getCollection : function() {
1345				return gridRoot.getCollection();
1346			},
1347			getDataSet : function() {
1348				return gridRoot.dataSet;
1349			},
1350			getSelectedRowData : function(num) {	// 선택된 row의 자료 읽기
1351				return gridRoot.dataSet[num];
1352			},
1353			getLastRowData : function() {	// 마지막 줄의 자료 읽기
1354				let dsLength = gridRoot.dataSet.length;
1355				if (dsLength > 0) {
1356					return gridRoot.dataSet[dsLength-1];
1357				}
1358				else {
1359					return undefined;
1360				}
1361			},
1362			getCurrentGridRoot : function() {
1363				return gridRoot;
1364			},
1365			setGridColumnTextValue(column_title, change_text) {
1366			    let selectorColumn = gridRoot.getObjectById("selector");
1367			    let selectedIndices = selectorColumn.getSelectedIndices();
1368
1369			    for (let i = 0; i < selectedIndices.length; i++) {
1370			        gridRoot.setItemFieldAt(change_text, selectedIndices[i], column_title);
1371			    }
1372			},
1373			removeSelected: function(selector) {
1374				gridRoot.removeSelectorColumnSelectedIndices(selector);
1375			},
1376			getRowCount: function() {
1377				return gridRoot.dataSet.length;
1378			},
1379			clear: function() {
1380				gridApp.setData([]);
1381			},
1382			noData: function() {
1383				this.showNoDataMessage("조회된 결과가 없습니다.");
1384				gridApp.setData([]);
1385			},
1386			showNoDataMessage: function(msg) {
1387				if (msg == null || msg == "") { msg = "조회된 결과가 없습니다."; }
1388				var messageLabel = gridRoot.getObjectById("messageLabel");
1389				if (messageLabel != undefined) {
1390					messageLabel.setText(msg);
1391				}
1392				var messageBox = gridRoot.getObjectById("messageBox");
1393				if (messageBox != undefined) {
1394					messageBox.setVisible(true);
1395				}
1396			},
1397			hideNoDataMessage: function() {
1398				var messageBox = gridRoot.getObjectById("messageBox");
1399				if (messageBox != undefined) {
1400					messageBox.setVisible(false);
1401				}
1402			},
1403			findText: function(str) {
1404			    // 검색할 문자열 지정
1405			    gridRoot.setSearchString(str);
1406			    dataGrid.setSelectionMode('singleCell');
1407			    // 검색 실행
1408			    var result = gridRoot.search(str);
1409
1410			    if (result == false) {
1411			        alert(str+ "을(를) 찾을 수 없습니다");
1412			    } else {
1413			    }
1414			    return result;
1415			},
1416			findTextPrev: function() {
1417				gridRoot.searchPrevious();
1418			},
1419			findTextNext: function() {
1420				gridRoot.searchNext();
1421			},
1422			isExists: function(searchColumn, searchStr) {
1423				let exists = false;
1424				const data = this.getGridData();
1425
1426				data.forEach(function(obj) {
1427					if (searchStr == obj[searchColumn]) {
1428						exists = true;
1429						return false;
1430					}
1431				});
1432
1433				return exists;
1434			},
1435			getOption: function() {
1436				return extOptions;
1437			},
1438			setColumnVisible(columnNo, check) {
1439			    dataGrid = gridRoot.getDataGrid();
1440			    columns = dataGrid.getColumns();
1441			    columns[columnNo].setVisible(check);
1442			},
1443			setLayout() {
1444				gridApp.setLayout(getLayoutStr(extOptions));
1445			}
1446			/*최재현 추가 그리드 리턴함수 시작*/
1447			,
1448			getGridData: function() {
1449				return gridRoot.getGridData();
1450			},
1451			resize : function() {
1452			    gridApp.resize();
1453			},
1454			getGridApp : function() {
1455			    return gridApp; //gridApp리턴
1456			},
1457			/*최재현 추가 그리드 리턴함수 끝*/
1458			// 수정 작업 결과 가져오기 (그리드에서 작업된 입력,수정,삭제 내용을 가져옵니다)
1459			// 데이터는 배열 형태로
1460			//  idx: 행번호
1461			//  job: 수행 작업 (I:입력, U:수정, D:삭제)
1462			//  data: 행의 자료
1463			//  를 가지고 있으며 삭제가 먼저 오도록 정렬되어 있습니다
1464			getChangedData : function() {
1465		  		var changedData = gridRoot.getChangedData();
1466			    if (changedData.length == 0){
1467					if( gridRoot.getRemoveAllData() ) {
1468			            //alert("전체 삭제 되었습니다.");
1469			        }else{
1470			           // alert("변경된 자료가 없습니다.");
1471					}
1472				}else{
1473					return changedData;
1474			    }
1475			} //hbkang 추가 그리드 행 삽입
1476		};
1477
1478		_isReturn = true;
1479
1480		return retObj;
1481	}
1482};
1483
1484StepEkt.getHtml = function(options) {
1485    defaultOption = {
1486        type: "GET",
1487        async: true,
1488        callback: function(html) {}
1489    };
1490    options = $.extend({}, defaultOption, options || {});
1491	/*2023-05-10 최재현 매개변수 data 추가 시작*/
1492    var data = options.data;
1493    if (data == undefined) {
1494        data = {};
1495    } else {
1496        if (data instanceof jQuery) {
1497            data = data.get(0)
1498        }
1499        if (data.nodeName == "FORM") {
1500            data = new FormData(data);
1501        }
1502    }
1503	/*2023-05-10 최재현 매개변수 data 추가 끝*/
1504    var ajaxData = {
1505        url: options.url,
1506        data: data,	/*2023-05-10 최재현 매개변수 data 추가*/
1507        type: options.type,
1508        async: options.async
1509    };
1510    StepEkt.blockUI();
1511    $.ajax(ajaxData).done(function(response) {
1512        options.callback(response);
1513    }).fail(function(response) {
1514    }).always(function(response) {
1515        StepEkt.unblockUI();
1516    });
1517};
1518
1519StepEkt.selectCmsVerInfo = function(options) {
1520	defaultOptions = {};
1521	options = $.extend({}, defaultOption, options || {});
1522	StepEkt.ajax({
1523		url: CP + "/coursemgmt/selectCmsVerInfoAjax.do",
1524		data: { verCd: options.verCd },
1525		method: "GET",
1526		success: function(data) {
1527			data.cmsLssnList.forEach(function(obj, idx) {
1528				obj.lssnNo = obj.nthSeq;
1529			});
1530			options.callback(data.cmsInfo, data.cmsLssnList, data.cmsNcsList, data.cmsPicList);
1531		}
1532	});
1533};
1534
1535StepEkt.selectpickerTitle = function() {
1536	// bs의  selectpicker 후에 option의 title을 selectpicker의 title로 처리한다.
1537	var $el = $(this);
1538	var $selectpicker = $el.data('selectpicker');
1539	var $element = $selectpicker.$element;
1540	var $elements = $selectpicker.selectpicker.main.elements;
1541	$element.find("option").each(function(idx, obj) {
1542		var tooltip_title = $(obj).attr('title');
1543		if (tooltip_title != null && tooltip_title != "") {
1544			$($elements[idx]).attr("title", tooltip_title);
1545		}
1546	});
1547};
1548
1549StepEkt.replaceChild = function($parents, nodeName, $selector, value) {
1550	let findStr = "";
1551	Object.keys($selector).forEach(function(key, idx) {
1552		findStr += "[" + key + "=" + $selector[key] + "]";
1553	});
1554	$parents.find(findStr).remove();
1555	let createEle = $("<" + nodeName + ">");
1556	Object.keys($selector).forEach(function(key, idx) {
1557		createEle.attr(key, $selector[key]);
1558	});
1559	createEle.val(value);
1560	$parents.append(createEle);
1561};
1562
1563StepEkt.createFormDataByAppId = function(appId, $app) {
1564	if ($app == null) {
1565		$app = $("[app=" + appId + "]");
1566	}
1567	const formData = new FormData();
1568	// set : 중복이름 불가
1569	// append : 중복이름 가능
1570
1571	$app.find("input").each(function(idx, obj) {
1572		const $obj = $(obj);
1573		const name = $obj.attr("name");
1574		const type = $obj.attr("type");
1575		const key = name + "_" + appId;
1576		console.log($obj.html());
1577		const hasKey = obj.hasAttribute(key);
1578		if (name != "" && hasKey) {
1579			if (type == "text") {
1580				formData.append(name, $obj.val());
1581			} else if (type == "hidden") {
1582				formData.append(name, $obj.val());
1583			} else if (type == "number") {
1584				formData.append(name, $obj.val());
1585			} else if (type == "file") {
1586				if (obj.files[0]) {
1587					formData.append(name, obj.files[0]);
1588				}
1589			} else if (type == "radio") {
1590				if ($obj.prop("checked")) {
1591					formData.append(name, $obj.val());
1592				}
1593			} else if (type == "checkbox") {
1594				if ($obj.prop("checked")) {
1595					formData.append(name, $obj.val());
1596				}
1597			}
1598		} else {
1599			console.error(obj);
1600		}
1601	});
1602
1603	$app.find("textarea").each(function(idx, obj) {
1604		const $obj = $(obj);
1605		const name = $obj.attr("name");
1606		const key = name + "_" + appId;
1607		const hasKey = obj.hasAttribute(key);
1608		if (name != "" && hasKey) {
1609			formData.append(name, $obj.val());
1610		}
1611	});
1612
1613	$app.find("select").each(function(idx, obj) {
1614		const $obj = $(obj);
1615		const name = $obj.attr("name");
1616		const type = $obj.attr("type");
1617		const key = name + "_" + appId;
1618		const hasKey = obj.hasAttribute(key);
1619		if (name != "" && hasKey) {
1620			formData.append(name, $obj.val());
1621		}
1622	});
1623
1624	(function() {
1625		for (const [key, value] of formData.entries()) {
1626			//console.log(key, value);
1627		}
1628	})();
1629
1630	return formData;
1631};
1632
1633StepEkt.doSampleDown = function(rfileName, sfileName) {
1634	const $iframe = $("<iframe style='display:none' width='0' height='0'></iframe>");
1635	$("body").append($iframe);
1636	$iframe.attr("src", CP + "/fileDownServlet?filePath=/sample&rFileName=" + rfileName + "&sFileName=" + sfileName);
1637	setTimeout(function() { $iframe.remove(); }, 60000);
1638};
1639
1640StepEkt.doFileDown = function(url) {
1641	const $form = $("<form target='_blank'>");
1642	$("body").append($form);
1643	$form.attr("action", url).submit();
1644	setTimeout(function() { $form.remove(); }, 60000);
1645};
1646
1647StepEkt.logoUrl = function(url) {
1648	if (url != null && (url.startsWith("/olei/") || url.startsWith("/Polaris/") || url.startsWith("/coursemaster/") || url.startsWith("/VT/") )) {
1649		return  CMS_FILE_GET_PATH + url;
1650	}
1651	return url;
1652};
1653
1654StepEkt.strLen = function(str) {
1655	const koreanMatches = str.match(/[가-힣]/g);
1656	const koreanLength = koreanMatches ? koreanMatches.length * 3 : 0;
1657	const nonKoreanLength = str.replace(/[가-힣]/g, '').length;
1658	const totalLength = koreanLength + nonKoreanLength;
1659	return totalLength;
1660};
1661
1662StepEkt.strCut = function(str, maxBytes) {
1663	let totalBytes = 0;
1664	let cutIndex = 0;
1665
1666	for (let i = 0; i < str.length; i++) {
1667		const charCode = str.charCodeAt(i);
1668		const byteSize = charCode < 128 ? 1 : 3; // UTF-8 기준
1669
1670		if (totalBytes + byteSize <= maxBytes) {
1671			totalBytes += byteSize;
1672			cutIndex = i + 1;
1673		} else {
1674			break;
1675		}
1676	}
1677
1678	return str.substring(0, cutIndex);
1679};
1680
1681StepEkt.scrollTop = function() {
1682	window.scrollTo(0, 0);
1683};
1684
1685StepEkt.scrollTopFrame = function() {
1686	try {
1687		parent.window.scrollTo(0, 0);
1688	} catch (e) {
1689		console.log(e);
1690	}
1691};
1692
1693StepEkt.scrollTop = function() {
1694	try {
1695		window.parent.postMessage({
1696			method : "scrollTop"
1697		},"*");
1698	} catch (e) {
1699		console.log(e);
1700	}
1701};
1702
1703StepEkt.parseQueryString = function(appendObject) {
1704	const queryString = window.location.search;
1705	const paramsObject = {};
1706
1707	if (queryString) {
1708		const paramsArray = queryString.slice(1).split('&');
1709		paramsArray.forEach(param => {
1710			const [key, value] = param.split('=');
1711			paramsObject[key] = value;
1712		});
1713	}
1714
1715	Object.keys(appendObject).forEach(key => {
1716		const value = appendObject[key];
1717		paramsObject[key] = value;
1718	});
1719
1720	return Object.entries(paramsObject).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&');
1721};

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.