PageSourceSearch

https://mportal.cau.ac.kr/common/axj/AXJ.js

js cau.ac.kr collected 2026-09-24 08:43:44 UTC 303,846 bytes, 8,655 lines download raw bytes

1/*! 
2axisj - v1.1.0 - 2016-03-07 
3*/
4
5if(!window.AXConfig){
6/**
7 * AXISJ UI 등에 기본값으로 사용되는 설정 변수
8 * @namespace {Object} AXConfig
9 * @example
10 ```json
11 AXConfig.weekDays = [{label:""},..];
12 AXConfig.AXReq.contentType = "";
13 // 처럼 기본값을 수정할 수 있습니다.
14 // .net 에서 webMethod를 이용하여 개발할 때는 다음의 설정을 권장합니다.
15 AXConfig.AXReq.okCode = "00";
16 AXConfig.AXReq.contentType = "application/json; charset=utf-8";
17 AXConfig.AXReq.dataSendMethod = "json";
18 AXConfig.AXReq.resultFormatter = function () {
19	return this.d.object();
20 };
21 ```
22 */
23	var AXConfig = {
24/**
25 * calendar weekDays label
26 * @memberof AXConfig
27 * @example
28 ```json
29 weekDays: [
30	 { label: "일" },
31	 { label: "월" },
32	 { label: "화" },
33	 { label: "수" },
34	 { label: "목" },
35	 { label: "금" },
36	 { label: "토" }
37 ]
38 ```
39 */
40		weekDays: [
41			{ label: "일" },
42			{ label: "월" },
43			{ label: "화" },
44			{ label: "수" },
45			{ label: "목" },
46			{ label: "금" },
47			{ label: "토" }
48		],
49/**
50 * AXReq default config
51 * @memberof AXConfig
52 * @example
53 ```json
54 AXReq: {
55	async: true, // AJAX 비동기 처리 여부
56	okCode: "ok", // 통신 성공 코드
57	responseType: "", // AJAX responseType
58	dataType: "", // AJAX return Data type
59	contentType: "application/x-www-form-urlencoded; charset=UTF-8", // AJAX contentType
60	dataSendMethod: "parameter", // AJAX parameter send type
61	crossDomain: false,
62	resultFormatter: function () { // onsucc formatter
63		return this;
64	}
65}
66 ```
67 */
68		AXReq: {
69			async: true, // AJAX 비동기 처리 여부
70			okCode: "ok", // 통신 성공 코드
71			responseType: "", // AJAX responseType
72			dataType: "", // AJAX return Data type
73			contentType: "application/x-www-form-urlencoded; charset=UTF-8", // AJAX contentType
74			dataSendMethod: "parameter", // AJAX parameter send type
75			crossDomain: false,
76			resultFormatter: function () { // onsucc formatter
77				return this;
78			}
79		},
80/**
81 * AXGrid default config
82 * @memberof AXConfig
83 * @example
84 ```json
85 AXGrid: {
86	passiveMode: false,
87	passiveRemoveHide: false,
88	fitToWidthRightMargin: 10,
89	fitToWidth: false,
90	pageSize: 10,
91	pageHeight: 400,
92	keyResult: "result",
93	keyList: "list",
94	emptyListMSG: "empty of list",
95	listCountMSG: "<b>{listCount}</b> count(s)",
96	pageCountMSG: "page(s)"
97}
98 ```
99 */
100		AXGrid: {
101			passiveMode: false,
102			passiveRemoveHide: false,
103			fitToWidthRightMargin: 11,
104			fitToWidth: false,
105			pageSize: 10,
106			pageHeight: 400,
107			headTdHeight: 30,
108			keyResult: "result",
109			keyList: "list",
110			emptyListMSG: "empty of list",
111			listCountMSG: "<b>{listCount}</b> count(s)",
112			pageCountMSG: "page(s)"
113		},
114/**
115 * AXTree default config
116 * @memberof AXConfig
117 * @example
118 ```json
119 AXTree: {
120	fitToWidthRightMargin: 10,
121	fitToWidth: false,
122	pageSize: 10,
123	pageHeight: 400,
124	keyResult: "result",
125	keyTree: "tree",
126	keyList: "list",
127	emptyListMSG: "목록이 없습니다.",
128	persist: true,
129    cookiePrefix: "axtree-",
130    cookieExpiredays: 7
131}
132 ```
133 */
134		AXTree: {
135			fitToWidthRightMargin: 10,
136			fitToWidth: false,
137			pageSize: 10,
138			pageHeight: 400,
139			keyResult: "result",
140			keyTree: "tree",
141			keyList: "list",
142			emptyListMSG: "목록이 없습니다.",
143			persistExpanded: false,
144			persistSelected: false,
145			cookiePrefix: "axtree-",
146			cookieExpiredays: 7
147		},
148/**
149 * AXProgress default config
150 * @memberof AXConfig
151 * @example
152 ```json
153 AXProgress: {
154	cancelMsg: "프로세스를 취소 하시겠습니까?"
155}
156 ```
157 */
158		AXProgress: {
159			cancelMsg: "프로세스를 취소 하시겠습니까?"
160		},
161/**
162 * AXUpload5 default config
163 * @memberof AXConfig
164 * @example
165 ```json
166 AXUpload5: {
167	buttonTxt: "Upload files",
168	deleteConfirm: "정말 삭제하시겠습니까?",
169	uploadSelectTxt: "업로드 하실 파일을 선택해주세요.",
170	dropZoneTxt: "업로드할 파일을 여기에 놓습니다."
171}
172 ```
173 */
174		AXUpload5: {
175			buttonTxt: "Upload files",
176			deleteConfirm: "정말 삭제하시겠습니까?",
177			uploadSelectTxt: "업로드 하실 파일을 선택해주세요.",
178			dropZoneTxt: "업로드할 파일을 여기에 놓습니다."
179		},
180/**
181 * AXModal default config
182 * @memberof AXConfig
183 * @example
184 ```json
185 AXModal: {
186	contentDivClass: "bodyHeightDiv"
187}
188 ```
189 */
190		AXModal: {
191			contentDivClass: "bodyHeightDiv",
192			pars: ""
193		},
194/**
195 * AXInput default config
196 * @memberof AXConfig
197 * @example
198 * ```json
199 * AXInput: {
200 * 	errorPrintType: "toast",
201 * 	selectorOptionEmpty: "목록이 없습니다.",
202 * 	yearText:"{year}년",
203 * 	monthText:"{month}월",
204 * 	confirmText:"확인",
205 * 	keyOptions:"options",
206 * 	keyOptionValue:"optionValue",
207 * 	keyOptionText:"optionText"
208 * }
209 * ```
210 */
211		AXInput: {
212			errorPrintType: "toast",
213			selectorOptionEmpty: "목록이 없습니다.",
214			yearText:"{year}년",
215			monthText:"{month}월",
216			confirmText:"확인",
217			keyOptions:"options",
218			keyOptionValue:"optionValue",
219			keyOptionText:"optionText"
220		},
221/**
222 * AXSelect default config
223 * @memberof AXConfig
224 * @example
225 * ```json
226 * AXSelect: {
227 *  keyOptions:"options",
228 *  keyOptionValue:"optionValue",
229 *  keyOptionText:"optionText"
230 * }
231 * ```
232 */
233		AXSelect: {
234			keyOptions:"options",
235			keyOptionValue:"optionValue",
236			keyOptionText:"optionText"
237		},
238/**
239 * AXContextMenu default config
240 * @memberof AXConfig
241 * @example
242 ```json
243 AXContextMenu: {
244	title:"선택하세요"
245}
246 ```
247 */
248		AXContextMenu: {
249			title:"선택하세요"
250		},
251/**
252 * mobile default config : 모바일 UI 반응너비
253 * @memberof AXConfig
254 * @example
255 ```json
256 mobile: {
257	responsiveWidth: 0
258}
259 ```
260 */
261		mobile: {
262			responsiveWidth: 0
263		},
264/**
265 * AXEditor default config
266 * @memberof AXConfig
267 * @example
268 ```json
269 AXEditor: {
270	editor_frameSrc : "/_AXJ/lib/AXEditor.html",
271	iconDirectory : "/ui/icons/"
272}
273 ```
274 */
275		AXEditor: {
276			editor_frameSrc : "/_AXJ/lib/AXEditor.html",
277			iconDirectory : "/ui/icons/"
278		},
279/**
280 * AXTab default config
281 * @memberof AXConfig
282 * @example
283 ```json
284 AXTab: {
285	closable : false
286 }
287 ```
288 */
289		AXTab: {
290			closable : false
291		},
292	/**
293	 * AXValidator default config
294	 * @memberof AXConfig
295	 * @example
296	 * ```json
297	 * AXValidator: {
298	 *	validateErrMessage: {
299	 *		required: "[{label}](은)는 필수입력 사항입니다.",
300	 *		requiredstring: "반드시 {required}(으)로 입력하셔야 하는 사항입니다.",
301	 *		match: "[{label}](은)는 입력된 내용이 일치하지 않습니다.",
302	 *		invalid: "[{label}](은)는 입력된 내용이 올바르지 않습니다.",
303	 *		min: "[{label}](은)는 {min} 이상의 값을 입력해주세요.",
304	 *		max: "[{label}](은)는 {max} 이하의 값을 입력해주세요.",
305	 *		minbyte: "[{label}]의 입력된 내용의 길이가 {minbyte}Byte 이상이어야 합니다.",
306	 *		maxbyte: "[{label}]의 입력된 내용의 길이가 {maxbyte}Byte를 초과할 수 없습니다.",
307	 *		minlength: "[{label}]의 입력된 내용의 length가 {minlength} 이상이어야 합니다.",
308	 *		maxlength: "[{label}]의 입력된 내용의 length가 {maxlength}을 초과할 수 없습니다.",
309	 *
310	 *		number: "숫자로만 입력하셔야 합니다.",
311	 *		email: "이메일 형식이 올바르지 않습니다.",
312	 *		hangul: "한글로만 입력하셔야 합니다.",
313	 *		engonly: "영문으로만 입력하셔야 합니다.",
314	 *		residentno: "주민등록번호 형식이 올바르지 않습니다.",
315	 *		foreignerno: "외국인등록번호 형식이 올바르지 않습니다.",
316	 *		bizno: "사업자등록번호 형식이 올바르지 않습니다.",
317	 *		phone: "전화번호 형식이 올바르지 않습니다.",
318	 *		isdate: "날짜 형식이 올바르지 않습니다.",
319	 *		zip: "우편번호 형식이 올바르지 않습니다.",
320	 *		money: "화폐형식으로만 입력하셔야 합니다.",
321	 *		earlierThan: "[{label}] 보다 빠른 날짜를 입력해야 합니다.",
322	 *		laterThan: "[{label}] 보다 느린 날짜를 입력해야 합니다.",
323	 *
324	 *		exception: "not found errmessage"
325	 *	}
326	 *}
327	 * ```
328 	 */
329		AXValidator: {
330			validateErrMessage: {
331				/* for element */
332				required: "[{label}](은)는 필수입력 사항입니다.",
333				requiredstring: "반드시 {required}(으)로 입력하셔야 하는 사항입니다.",
334				match: "[{label}](은)는 입력된 내용이 일치하지 않습니다.",
335				invalid: "[{label}](은)는 입력된 내용이 올바르지 않습니다.",
336				min: "[{label}](은)는 {min} 이상의 값을 입력해주세요.",
337				max: "[{label}](은)는 {max} 이하의 값을 입력해주세요.",
338				minbyte: "[{label}]의 입력된 내용의 길이가 {minbyte}Byte 이상이어야 합니다.",
339				maxbyte: "[{label}]의 입력된 내용의 길이가 {maxbyte}Byte를 초과할 수 없습니다.",
340				minlength: "[{label}]의 입력된 내용의 length가 {minlength} 이상이어야 합니다.",
341				maxlength: "[{label}]의 입력된 내용의 length가 {maxlength}을 초과할 수 없습니다.",
342
343				/* for format */
344				number: "숫자로만 입력하셔야 합니다.",
345				email: "이메일 형식이 올바르지 않습니다.",
346				hangul: "한글로만 입력하셔야 합니다.",
347				engonly: "영문으로만 입력하셔야 합니다.",
348				residentno: "주민등록번호 형식이 올바르지 않습니다.",
349				foreignerno: "외국인등록번호 형식이 올바르지 않습니다.",
350				bizno: "사업자등록번호 형식이 올바르지 않습니다.",
351				phone: "전화번호 형식이 올바르지 않습니다.",
352				isdate: "날짜 형식이 올바르지 않습니다.",
353				zip: "우편번호 형식이 올바르지 않습니다.",
354				money: "화폐형식으로만 입력하셔야 합니다.",
355				earlierThan: "[{label}] 보다 빠른 날짜를 입력해야 합니다.",
356				laterThan: "[{label}] 보다 느린 날짜를 입력해야 합니다.",
357
358				exception: "not found errmessage"
359			}
360		}
361	};
362}
363/* ---------------------------- */
364var axf = AXUtil = {
365    async: true,
366    ajaxOkCode: "ok",
367    ajaxResponseType: "",
368    ajaxDataType: "",
369    gridPassiveMode: false,
370    gridPassiveRemoveHide: false,
371    gridFitToWidthRightMargin: 10,
372
373    uniqueSeq: 0,
374
375    /**
376     * 현재페이지에서 고유한 순번을 반환합니다.
377     * @method axf.getUniqueId
378     * @returns {Number} uniqueSeq
379     * @example
380     * ```js
381     * trace( axf.getUniqueId() );
382     * ```
383     */
384    getUniqueId: function () { return (axf.uniqueSeq += 1); },
385
386    /**
387     * document.getElementById(id) 와 같습니다. 아이디가 같은 엘리먼트를 반환합니다.
388     * @method axf.getId
389     * @param {String} id
390     * @returns {HtmlElement}
391     * @example
392     * ```js
393     * if(axf.getId("myele_id")){
394	 *    $("#myele_id").css({...});
395	 * }
396     * ```
397     */
398    getId: function (id) { return document.getElementById(id); },
399
400    /**
401     * @method axf.each
402     * @param {Array|Object} obj
403     * @param {Function} callback
404     * @description Array 또는 Object의 아이템만큰 callback 함수를 call합니다.
405     * @example
406     * ```js
407     * var new_array = [];
408     * axf.each([0, 1, 2], function(){
409	 * 	new_array.push(this*2);
410	 * });
411     * var new_object = {};
412     * axf.each({a:1, b:2, c:3}, function(k, v){
413	 * 	new_object[k] = v*2;
414	 * });
415     * ```
416     */
417    each: function (obj, callback) {
418        if (obj) {
419            var name, i = 0, length = obj.length,
420                isObj = length === undefined || Object.isFunction(obj);
421            if (isObj) {
422                for (name in obj) {
423                    if (callback.call(obj[name], name, obj[name]) === false) {
424                        break;
425                    }
426                }
427            }
428            else {
429                for (; i < length;) {
430                    if (callback.call(obj[i], i, obj[i++]) === false) {
431                        break;
432                    }
433                }
434            }
435        }
436    },
437    /**
438     * 브라우저의 이름과 버전 모바일여부
439     *
440     * @member {Object} axf.browser
441     * @example
442     * ```js
443     *{
444     *	name: {String} - bowserName (ie|chrome|webkit|oprea),
445     *	version: {Number} - browserVersion,
446     *	mobile: {Boolean}
447     *}
448     * ```
449     */
450    browser: (function () {
451        var ua = navigator.userAgent.toLowerCase();
452        var mobile = (ua.search(/mobile/g) != -1);
453        if (ua.search(/iphone/g) != -1) {
454            return {name: "iphone", version: 0, mobile: true}
455        }
456        else if (ua.search(/ipad/g) != -1) {
457            return {name: "ipad", version: 0, mobile: true}
458        }
459        else if (ua.search(/android/g) != -1) {
460            var match = /(android)[ \/]([\w.]+)/.exec(ua) || [];
461            var browserVersion = (match[2] || "0");
462            return {name: "android", version: browserVersion, mobile: mobile}
463        }
464        else {
465            var match = /(msie) ([\w.]+)/.exec(ua) ||
466                /(trident)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
467                /(opera|opr)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
468                /(chrome)[ \/]([\w.]+)/.exec(ua) ||
469                /(webkit)[ \/]([\w.]+)/.exec(ua) ||
470                ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
471                [];
472
473            var browser = (match[1] || "");
474            var browserVersion = (match[2] || "0");
475
476            var browserName = {
477                "msie": "ie",
478                "trident": "ie",
479                "opr": "opera"
480            };
481            if (browser in browserName) browser = browserName[browser];
482
483            return {
484                name: browser,
485                version: browserVersion,
486                mobile: mobile
487            }
488        }
489    })(),
490    /**
491     * 호환성보기 여부
492     * @member {String} axf.docTD
493     * @example
494     * ```js
495     * axf.docTD = (Q|S)
496     * ```
497     */
498    docTD: (function () {
499        if (!document.compatMode || document.compatMode == 'BackCompat') return "Q";
500        else return "S";
501    })(),
502    /**
503     * @method axf.timekey
504     * @returns {String} timeKey
505     * @description 밀리세컨드까지 조합한 문자열을 반환합니다.
506     * @example
507     * ```js
508     * trace(axf.timeKey()); // A004222760
509     * ```
510     */
511    timekey: function () {
512        var d = new Date();
513        return ("A" + d.getHours().setDigit(2) + d.getMinutes().setDigit(2) + d.getSeconds().setDigit(2) + d.getMilliseconds());
514    },
515    /**
516     * @method axf.overwriteObject
517     * @param {Object} tg - 덮어쓰기 대상 오브젝트
518     * @param {Object} obj - 덮어쓰기 할 오브젝트
519     * @param {Boolean} [rewirte=false] - 덮어쓰기 모드
520     * @returns {Object} 덮어쓰기된 tg
521     * @description 덮어쓰기 대상 오브젝트에 덮어쓰기 할 오브젝트를 덮어쓰기 합니다.
522     * @example
523     * ```js
524     * axf.overwriteObject({a:1}, {b:1});
525     * // {a:1, b:1}
526     * axf.overwriteObject({a:1}, {a:2}, true);
527     * // {a:2}
528     * // rewirte : false 이면 {a:1} 로 유지 됩니다. 대상오브젝트에 키가 없는 경우에만 덮어쓰기 합니다.
529     * ```
530     */
531    overwriteObject: function (tg, obj, rewrite) {
532        if (rewrite == undefined) rewrite = true;
533        //trace(tg[k]);
534        if (obj) AXUtil.each(obj, function (k, v) {
535            if (rewrite) {
536                tg[k] = v;
537            }
538            else {
539                //trace(tg[k]);
540                if (tg[k] == undefined) tg[k] = v;
541            }
542        });
543        return tg;
544    },
545    /**
546     * @method axf.copyObject
547     * @param {Object} obj - 복제할 오브젝트
548     * @returns {Object} 복제된 오브젝트
549     * @description 오브젝트를 복제하여 새로운 참조를 리턴합니다.
550     * @example
551     * ```js
552     * axf.copyObject({a:1});
553     * // 내부코드가 Object.toJSON(obj).object(); 이므로 상황에 맞게 사용해야 합니다.
554     * ```
555     */
556    copyObject: function (obj) {
557        //return Object.clone(obj);
558        return Object.toJSON(obj).object();
559    },
560    consonantKR: function (cword) {
561        var cons = [
562            {c: "ㄱ", re: "[가-깋]"}, {c: "ㄲ", re: "[까-낗]"}, {c: "ㄴ", re: "[나-닣]"}, {c: "ㄷ", re: "[다-딯]"}, {c: "ㄸ", re: "[따-띻]"}, {c: "ㄹ", re: "[라-맇]"},
563            {c: "ㅁ", re: "[마-밓]"}, {c: "ㅂ", re: "[바-빟]"}, {c: "ㅃ", re: "[빠-삫]"}, {c: "ㅅ", re: "[사-싷]"}, {c: "ㅆ", re: "[싸-앃]"}, {c: "ㅇ", re: "[아-잏]"}, {c: "ㅈ", re: "[자-짛]"},
564            {c: "ㅉ", re: "[짜-찧]"}, {c: "ㅊ", re: "[차-칳]"}, {c: "ㅋ", re: "[카-킿]"}, {c: "ㅌ", re: "[타-팋]"}, {c: "ㅍ", re: "[파-핗]"}, {c: "ㅎ", re: "[하-힣]"},
565            {c: "(", re: "\\("}, {c: ")", re: "\\)"}, {c: "[", re: "\\["}, {c: "]", re: "\\]"}
566        ];
567        var rword = "";
568        var cwords = cword.split("");
569        for (var i = 0, l = cwords.length; i < l; i++) {
570            var fos = cons.searchObject(function () {
571                return this.item.c == cwords[i];
572            });
573            var fo = fos.first();
574            if (fo) rword += fo.re;
575            else rword += cwords[i];
576        }
577        return rword;
578    },
579    /**
580     * @method axf.setCookie
581     * @param {String} name
582     * @param {String} value
583     * @param {Number} [expiredays]
584     * @param {Object} options
585     * @description 쿠키에 값을 지정합니다.
586     * @example
587     * ```js
588     * axf.setCookie("myname", "tomas", 10, {
589	 *     path  : "/",             // {String} [현재 페이지의 path]
590	 *     domain: "www.axisj.com", // {String} [현재 사이트의 domain]
591	 *     secure: true             // {Boolean} [false]
592	 * });
593     * ```
594     */
595    setCookie: function (name, value, expiredays, options) {
596        var expireDate;
597        if (typeof expiredays === "number") {
598            expireDate = new Date();
599            expireDate.setDate(expireDate.getDate() + expiredays);
600        }
601
602        options = options || {};
603
604        return (document.cookie = [
605            encodeURIComponent(name), '=', String(value),
606            expireDate ? "; expires=" + expireDate.toUTCString() : "", // use expires attribute, max-age is not supported by IE
607            options.path ? "; path=" + options.path : "",
608            options.domain ? "; domain=" + options.domain : "",
609            options.secure ? "; secure" : ""
610        ].join(""));
611    },
612    /**
613     * @method axf.getCookie
614     * @param {String} name
615     * @description 쿠키에서 값을 읽어들입니다
616     * @example
617     * ```js
618     * trace( axf.getCookie("myname") );
619     * // tomas
620     * ```
621     */
622    getCookie: function (name) {
623        var nameOfCookie = name + "=";
624        var x = 0;
625        while (x <= document.cookie.length) {
626            var y = (x + nameOfCookie.length);
627            if (document.cookie.substring(x, y) == nameOfCookie) {
628                if ((endOfCookie = document.cookie.indexOf(";", y)) == -1) endOfCookie = document.cookie.length;
629                return decodeURIComponent(document.cookie.substring(y, endOfCookie));
630            }
631            x = document.cookie.indexOf(" ", x) + 1;
632            if (x == 0) break;
633        }
634        return "";
635    },
636    JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
637    /**
638     * @method axf.dayLen
639     * @param {Number} year
640     * @param {Number} month
641     * @returns {Number} end of daynum
642     * @description 지정한 년도와 월의 날자수를 반환합니다.
643     * @example
644     * ```js
645     * trace( axf.dayLen(2013, 1) );
646     * // 28
647     * // 주의 Data.getMonth() 의 반환값을 그대로 사용 하므로 1월은 0 으로 전달 해야 합니다. 0~11 까지의 값을 사용할 수 있습니다.
648     * ```
649     */
650    dayLen: function (y, m) {
651        if ([3, 5, 8, 10].has(function () { return this.item == m; })) {
652            return 30;
653        }
654        else if (m == 1) {
655            return (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)) ? 29 : 28;
656        }
657        else {
658            return 31;
659        }
660    },
661    /**
662     * @method  axf.clientHeight
663     * @returns {Number} clientHeight
664     * @description 브라우저 clientHeight 반환합니다. window 창 높이와 같습니다.
665     * @example
666     * ```js
667     * axf.clientHeight();
668     * ```
669     */
670    clientHeight: function () { return (AXUtil.docTD == "Q") ? document.body.clientHeight : document.documentElement.clientHeight; },
671    /**
672     * @method  axf.scrollHeight
673     * @returns {Number} scrollHeight
674     * @description HTML scrollHeight 반환합니다.
675     * @example
676     * ```js
677     * axf.scrollHeight();
678     * ```
679     */
680    scrollHeight: function () { return (AXUtil.docTD == "Q") ? document.body.scrollHeight : document.documentElement.scrollHeight; },
681    /**
682     * @method  axf.clientWidth
683     * @returns {Number} clientWidth
684     * @description 브라우저 clientWidth 반환합니다. window 창 너비와 같습니다.
685     * @example
686     * ```js
687     * axf.clientWidth();
688     * ```
689     */
690    clientWidth: function () { return (AXUtil.docTD == "Q") ? document.body.clientWidth : document.documentElement.clientWidth; },
691    /**
692     * @method  axf.scrollWidth
693     * @returns {Number} scrollWidth
694     * @description HTML scrollWidth 반환합니다.
695     * @example
696     * ```js
697     * axf.scrollWidth();
698     * ```
699     */
700    scrollWidth: function () { return (AXUtil.docTD == "Q") ? document.body.scrollWidth : document.documentElement.scrollWidth; },
701    scrollTop: function () {
702        return (document.documentElement && document.documentElement.scrollTop) ||
703            document.body.scrollTop;
704    },
705    scrollLeft: function () {
706        return (document.documentElement && document.documentElement.scrollLeft) ||
707            document.body.scrollLeft;
708    },
709    /**
710     * @member {Object} axf.Event
711     * @description Event.keyCode 모음 ref => https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
712     * @example
713     * ```js
714     *Event: {
715	 *    KEY_BACKSPACE: 8,
716	 *    KEY_TAB      : 9,
717	 *    KEY_RETURN   : 13,
718	 *    KEY_SHIFT    : 16,
719	 *    KEY_CONTROL  : 17,
720	 *    KEY_ALT      : 18,
721	 *    KEY_ESC      : 27,
722	 *    KEY_SPACE    : 32,
723	 *    KEY_PAGEUP   : 33,
724	 *    KEY_PAGEDOWN : 34,
725	 *    KEY_END      : 35,
726	 *    KEY_HOME     : 36,
727	 *    KEY_LEFT     : 37,
728	 *    KEY_UP       : 38,
729	 *    KEY_RIGHT    : 39,
730	 *    KEY_DOWN     : 40,
731	 *    KEY_INSERT   : 45,
732	 *    KEY_DELETE   : 46,
733	 *    KEY_WINDOW   : 91,
734	 *    KEY_EQUAL    : 187,
735	 *    KEY_MINUS    : 189,
736	 *    KEY_PERIOD   : 190,
737	 *    NUMPAD_EQUAL   : 12,
738	 *    NUMPAD_MULTIPLY: 106,
739	 *    NUMPAD_ADD     : 107,
740	 *    NUMPAD_SUBTRACT: 109,
741	 *    NUMPAD_DECIMAL : 110,
742	 *    NUMPAD_DIVIDE  : 111,
743	 *    NUMPAD_COMMA   : 194,
744	 *    cache: {}
745	 *}
746     * ```
747     */
748    Event: {
749        KEY_BACKSPACE: 8,
750        KEY_TAB: 9,
751        KEY_RETURN: 13,
752        KEY_SHIFT: 16,
753        KEY_CONTROL: 17,
754        KEY_ALT: 18,
755        KEY_ESC: 27,
756        KEY_SPACE: 32,
757        KEY_PAGEUP: 33,
758        KEY_PAGEDOWN: 34,
759        KEY_END: 35,
760        KEY_HOME: 36,
761        KEY_LEFT: 37,
762        KEY_UP: 38,
763        KEY_RIGHT: 39,
764        KEY_DOWN: 40,
765        KEY_INSERT: 45,
766        KEY_DELETE: 46,
767        KEY_WINDOW: 91,
768        KEY_EQUAL: 187,
769        KEY_MINUS: 189,
770        KEY_PERIOD: 190,
771        NUMPAD_EQUAL: 12,
772        NUMPAD_MULTIPLY: 106,
773        NUMPAD_ADD: 107,
774        NUMPAD_SUBTRACT: 109,
775        NUMPAD_DECIMAL: 110,
776        NUMPAD_DIVIDE: 111,
777        NUMPAD_COMMA: 194,
778        cache: {}
779    },
780    /**
781     * @method axf.console
782     * @param {String|Object|Array} obj
783     * @description 브라우저 console 에 메세지를 출력하여 줍니다. trace 와 같습니다.
784     * @example
785     * ```js
786     * axf.console("AXISJ");
787     * // AXISJ
788     *
789     * axf.console(1234);
790     * // 1234
791     *
792     * var myObj = {name:"AXISJ", url:"http://www.axisj.com"};
793     * axf.console(myObj);
794     * // {"name":"AXISJ", "url":"http://www.axisj.com"}
795     * ```
796     */
797    console: function (obj) {
798        var po = "";
799        if (arguments.length > 1) {
800            for (i = 0; i < arguments.length; i++) {
801                var obji = arguments[i];
802                var objStr = "";
803                var type = (typeof obji).toLowerCase();
804                if (type == "undefined" || type == "function") {
805                    objStr = type;
806                }
807                else if (type == "boolean" || type == "number" || type == "string") {
808                    objStr = obji;
809                }
810                else if (type == "object") {
811                    objStr = Object.toJSON(obji);
812                }
813                if (po != "") po += ", ";
814                po += "arg[" + i + "] : " + objStr;
815            }
816        }
817        else {
818            var type = (typeof obj).toLowerCase();
819            if (type == "undefined" || type == "function") {
820                po = type;
821            }
822            else if (type == "boolean" || type == "number" || type == "string") {
823                po = obj;
824            }
825            else if (type == "object") {
826                po = Object.toJSON(obj);
827            }
828        }
829
830        if (axf.mobileConsole) {
831            axf.mobileConsole.prepend("<div>" + po + "</div>");
832        }
833        else {
834            if (window.console == undefined) {
835            }
836            else {
837                try {
838                    console.log(po);
839                    //+ ":" + axf.console.caller.name
840                } catch (e) {
841                    alert(e);
842                }
843            }
844        }
845    },
846    /**
847     * @method  axf.alert
848     * @param {String|Object|Array} obj
849     * @description window.alert 를 확장하여 JSObject 구조를 출력 합니다.
850     * @example
851     * ```js
852     * axf.alert("AXISJ");
853     * // AXISJ
854     *
855     * axf.alert(1234);
856     * // 1234
857     *
858     * var myObj = {name:"AXISJ", url:"http://www.axisj.com"};
859     * axf.alert(myObj);
860     * // {"name":"AXISJ", "url":"http://www.axisj.com"}
861     * ```
862     */
863    alert: function (obj) {
864        var po = "";
865        if (arguments.length > 1) {
866            for (i = 0; i < arguments.length; i++) {
867                var obji = arguments[i];
868                var objStr = "";
869                var type = (typeof obji).toLowerCase();
870                if (type == "undefined" || type == "function") {
871                    objStr = type;
872                }
873                else if (type == "boolean" || type == "number" || type == "string") {
874                    objStr = obji;
875                }
876                else if (type == "object") {
877                    objStr = Object.toJSON(obji);
878                }
879                if (po != "") po += ", ";
880                po += "arguments[" + i + "] : " + objStr;
881            }
882        }
883        else {
884            var type = (typeof obj).toLowerCase();
885            if (type == "undefined" || type == "function") {
886                po = type;
887            }
888            else if (type == "boolean" || type == "number" || type == "string") {
889                po = obj;
890            }
891            else if (type == "object") {
892                po = Object.toJSON(obj);
893            }
894        }
895        alert(po);
896    },
897    /**
898     * @method  axf.confirm
899     * @param {String|Object|Array} obj
900     * @description window.confirm 를 확장하여 JSObject 구조를 출력 합니다.
901     * @example
902     * ```js
903     * axf.confirm("AXISJ");
904     * // AXISJ
905     *
906     * axf.confirm(1234);
907     * // 1234
908     *
909     * var myObj = {name:"AXISJ", url:"http://www.axisj.com"};
910     * axf.confirm(myObj);
911     * // {"name":"AXISJ", "url":"http://www.axisj.com"}
912     * ```
913     */
914    confirm: function (obj) {
915        var po = "";
916        var type = (typeof obj).toLowerCase();
917        if (type == "undefined" || type == "function") {
918            po = type;
919        }
920        else if (type == "boolean" || type == "number" || type == "string") {
921            po = obj;
922        }
923        else if (type == "object") {
924            po = Object.toJSON(obj);
925        }
926        var result = confirm(po);
927        return result;
928    },
929    importJS: function (src) {
930        var scriptElement = document.createElement("script");
931        scriptElement.setAttribute("src", src);
932        scriptElement.setAttribute("type", "text/javascript");
933        document.getElementsByTagName("head")[0].appendChild(scriptElement);
934    },
935    bindPlaceholder: function () {
936
937    },
938    /**
939     * @method axf.isEmpty
940     * @param {obj} obj
941     * @returns {Boolean}
942     * @description 대상 개체가 undefined, null, "" 인지 체크 합니다.
943     * @example
944     * ```js
945     * trace( axf.isEmpty("AXISJ") );
946     * // false
947     * trace( axf.isEmpty("") );
948     * // true
949     * trace( axf.isEmpty(undefined) );
950     * // true
951     * ```
952     */
953    isEmpty: function (obj) {
954        return (obj === "" || obj === null || obj === undefined);
955    },
956    /**
957     * @method axf.getUrlInfo
958     * @returns {Object} urlInfo
959     * @description 브라우저 각종 속성을 반환합니다.
960     * @example
961     * ```js
962     * trace( axf.getUrlInfo() );
963     * {
964	 * 	"url":"http://127.0.0.1:2013/samples/AXcore/test.html",
965	 * 	"param":"",
966	 * 	"anchorData":"127.0.0.1:2013/samples/AXcore/test.html",
967	 * 	"urlParam":"http://127.0.0.1:2013/samples/AXcore/test.html",
968	 * 	"referUrl":"",
969	 * 	"pathName":"/samples/AXcore/test.html",
970	 * 	"protocol":"http:",
971	 * 	"hostName":"127.0.0.1"
972	 * }
973     * ```
974     */
975    getUrlInfo: function () {
976        var url, url_param, param, referUrl, pathName, AXparam, pageProtocol, pageHostName;
977        url_param = window.location.href;
978        param = window.location.search;
979        referUrl = document.referrer;
980        pathName = window.location.pathname;
981        url = url_param.replace(param, '');
982        param = param.replace(/^\?/, '');
983        pageProtocol = window.location.protocol;
984        pageHostName = window.location.hostname;
985        AXparam = url_param.replace(pageProtocol + "//", "");
986        AXparam = (param) ? AXparam.replace(pageHostName + pathName + "?" + param, "") : AXparam.replace(pageHostName + pathName, "");
987        return {
988            url: url,
989            param: param,
990            anchorData: AXparam,
991            urlParam: url_param,
992            referUrl: referUrl,
993            pathName: pathName,
994            protocol: pageProtocol,
995            hostName: pageHostName
996        };
997    },
998    /**
999     * @method axf.encParam
1000     * @param {String} str - parameter
1001     * @returns {String} parameter
1002     * @description 파라미터에 value를 URLEncode해 줍니다.
1003     * @example
1004     * ```js
1005     * axf.encParam("name=장기영&sex=남");
1006     * //"name=%EC%9E%A5%EA%B8%B0%EC%98%81&sex=%EB%82%A8"
1007     * ```
1008     */
1009    encParam: function (str) {
1010        var re = new RegExp("[^&?]*?=[^&?]*", "ig");
1011        var pars = [];
1012        var arr;
1013        while ((arr = re.exec(str)) != null) {
1014            var strContent = arr.toString();
1015            var dotIndex = strContent.indexOf("=");
1016            pars.push(strContent.substring(0, dotIndex) + "=" + strContent.substring(dotIndex + 1).enc());
1017        }
1018        return pars.join("&");
1019    },
1020    readyMobileConsole: function () {
1021        AXUtil.mobileConsole = axdom("<div class=\"AXMobileConsole\"></div>");
1022        axdom(document.body).append(AXUtil.mobileConsole);
1023    },
1024    parsingTable: function (elemObj, returnType) {
1025        var head = {}, body = [];
1026        elemObj.find("thead tr td").each(function () {
1027            var elem = axdom(this);
1028            var attrs = {
1029                key: elem.attr("name"),
1030                label: (elem.html() || ""),
1031                width: (elem.attr("width") || "*"),
1032                align: (elem.attr("align") || "")
1033            };
1034            head[attrs.key] = attrs;
1035        });
1036
1037        elemObj.find("tbody tr").each(function () {
1038            var item = {};
1039            axdom(this).find("td").each(function () {
1040                var elem = axdom(this);
1041                item[elem.attr("name")] = elem.html();
1042            });
1043            body.push(item);
1044        });
1045        return {
1046            head: head, body: body
1047        };
1048    },
1049    /**
1050     * @member {type} axf.mousewheelevt
1051     * @description 브라우저에 따른 마우스 휠 이벤트이름
1052     */
1053    mousewheelevt: ((/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel"),
1054
1055    //todo : event bubble catch
1056    /**
1057     * 타겟엘리먼트의 부모 엘리멘트에서 원하는 조건의 엘리먼트를 얻습니다.
1058     * @method axf.get_event_target
1059     * @param {Element} target - target element
1060     * @param {Object} cond - 원하는 element를 찾을 조건
1061     * @returns {Element}
1062     * @example
1063     * ```js
1064     * console.log(axf.get_event_target(e.target, {tagname:"a", clazz:"findclass", etc:"attribute"}));
1065     * ```
1066     */
1067    get_event_target: function (target, cond) {
1068        var _target = target;
1069        if (_target) {
1070            while ((function () {
1071                var result = true;
1072                if (Object.isFunction(cond)) {
1073                    result = cond(_target);
1074                }
1075                else if (Object.isObject(cond)) {
1076                    for (var k in cond) {
1077                        if (k === "tagname") {
1078                            if (_target.tagName.lcase() != cond[k]) {
1079                                result = false;
1080                                break;
1081                            }
1082                        }
1083                        else if (k === "clazz") {
1084                            var klasss = _target.className.split(/ /g);
1085                            var hasClass = false;
1086                            for (var a = 0; a < klasss.length; a++) {
1087                                if (klasss[a] == cond[k]) {
1088                                    hasClass = true;
1089                                    break;
1090                                }
1091                            }
1092                            result = hasClass;
1093                        }
1094                        else { // 그외 속성값들.
1095                            if (_target.getAttribute) {
1096                                if (_target.getAttribute(k) != cond[k]) {
1097                                    result = false;
1098                                    break;
1099                                }
1100                            }
1101                            else {
1102                                result = false;
1103                                break;
1104                            }
1105                        }
1106                    }
1107                }
1108                return !result;
1109            })())
1110            {
1111                if (_target.parentNode) {
1112                    _target = _target.parentNode;
1113                }
1114                else {
1115                    _target = false;
1116                    break;
1117                }
1118            }
1119        }
1120        return _target;
1121    }
1122};
1123var axdom;
1124if (window.jQuery) axdom = jQuery;
1125if (window.axdomConverter) axdom = axdomConverter;
1126
1127// extend implement block
1128
1129/**
1130 * AXISJ Class 지원 오브젝트
1131 * @namespace {Object} Class
1132 */
1133var Class = (function () {
1134    function subclass() { }
1135
1136    /**
1137     * @method Class.create
1138     * @param {Object} [superClass] - 부모 클래스 오브젝트
1139     * @param {Object} Class Body
1140     * @description 클래스를 만들어 줍니다.
1141     * @example
1142     * ```js
1143     * var AXJ = Class.create({
1144 *	initialize: function () {
1145 *		this.config = {
1146 *			debugMode: false,
1147 *			hashSpliter: "_",
1148 *			href: "href=\"javascript:;\""
1149 *		};
1150 *	},
1151 *	init: function () {
1152 *		trace(Object.toJSON(this.config));
1153 *	}
1154 * });
1155     * ```
1156     */
1157    function create() {
1158        var parent = null, properties = AX_A(arguments);
1159        if (Object.isFunction(properties[0])) parent = properties.shift();
1160        function klass() { this.initialize.apply(this, arguments); }
1161
1162        Object.extend(klass, Class.Methods);
1163        klass.superclass = parent;
1164        klass.subclasses = [];
1165        if (parent) {
1166            subclass.prototype = parent.prototype;
1167            klass.prototype = new subclass;
1168            parent.subclasses.push(klass);
1169        }
1170        for (var i = 0; i < properties.length; i++) klass.addMethods(properties[i]);
1171        if (!klass.prototype.initialize) klass.prototype.initialize = Prototype.emptyFunction;
1172        klass.prototype.constructor = klass;
1173        return klass;
1174    }
1175
1176    function addMethods(source) {
1177        var ancestor = this.superclass && this.superclass.prototype;
1178        var properties = Object.keys(source);
1179        if (!Object.keys({toString: true}).length) {
1180            if (source.toString != Object.prototype.toString) properties.push("toString");
1181            if (source.valueOf != Object.prototype.valueOf) properties.push("valueOf");
1182        }
1183        for (var i = 0, length = properties.length; i < length; i++) {
1184            var property = properties[i], value = source[property];
1185            if (ancestor && Object.isFunction(value) && value.argumentNames().first() == "AXJ_super") {
1186                var method = value;
1187                value = (function (m) { return function () { return ancestor[m].apply(this, arguments); }; })(property).wrap(method);
1188                value.valueOf = method.valueOf.bind(method);
1189                value.toString = method.toString.bind(method);
1190            }
1191            this.prototype[property] = value;
1192        }
1193        return this;
1194    }
1195
1196    return {create: create, Methods: {addMethods: addMethods}};
1197})();
1198
1199/**
1200 * Object.prototype
1201 * @namespace {Object} Object
1202 */
1203    // Object extend
1204(function () {
1205    var _toString = Object.prototype.toString;
1206    //function extend(destination, source) { for (var property in source) destination[property] = source[property]; return destination; }
1207
1208    /**
1209     * @method Object.extend
1210     * @param {Object} [target]
1211     * @param {Object} extend object
1212     * @param {Boolean} [overwrite=false] - 덮어쓰기 여부
1213     * @returns {Object} extended object
1214     * @description 오브젝트를 확장합니다. 타겟 오브젝트에 확장오브젝트의 키를 추가하거나 덮어쓰기 합니다.
1215     * @example
1216     * ```js
1217     * Object.extend({a:1}, {a:2});
1218     * // Object {a: 1}
1219     * Object.extend({a:1}, {b:2});
1220     * // Object {a: 1, b: 2}
1221     * Object.extend({a:1}, {a:2}, true);
1222     * // Object {a: 2}
1223     * ```
1224     */
1225    function extend() {
1226        var target = arguments[0] || {}, items = arguments[1], overwrite = arguments[2] || false;
1227        if (typeof target !== "object" && typeof target !== "function") {
1228            target = {};
1229        }
1230        if (typeof items === "string") {
1231            target = items;
1232        }
1233        else {
1234            if (overwrite === true) {
1235                for (var k in items) target[k] = items[k];
1236            }
1237            else if (overwrite === false) {
1238                for (var k in items) {
1239                    if (typeof target[k] === "undefined") target[k] = items[k];
1240                }
1241            }
1242        }
1243        return target;
1244    }
1245
1246    function inspect(obj) {
1247        try {
1248            if (isUndefined(obj)) return 'undefined';
1249            if (obj === null) return 'null';
1250            return obj.inspect ? obj.inspect() : String(obj);
1251        } catch (e) {
1252            if (e instanceof RangeError) return '...';
1253            throw e;
1254        }
1255    }
1256
1257    /**
1258     * @method Object.toJSON
1259     * @param {Object} object
1260     * @param {Boolean} [qoute=true] - 따옴표 표시 여부
1261     * @returns {String} JSON String
1262     * @description Object JSON String 으로 반환합니다. Function은 제외합니다.
1263     * @example
1264     * ```js
1265     * Object.toJSON({a:1, b:2});
1266     * // "{"a":1, "b":2}"
1267     * Object.toJSON({a:1, b:2}, false);
1268     * // "{a:1, b:2}"
1269     * ```
1270     */
1271
1272    var toJSON = (function () {
1273        var r = /["]/g, f;
1274        return f = function (vContent, isqoute) {
1275            var result, i, j;
1276            switch (result = typeof vContent) {
1277                case'string':
1278                    return '"' + vContent.replace(r, '\\"') + '"';
1279                case'number':
1280                    return vContent;
1281                case'boolean':
1282                    return vContent.toString();
1283                case'undefined':
1284                    return 'undefined';
1285                case'function':
1286                    return '""';
1287                case'object':
1288                    if(_toString.call(vContent) == "[object Number]"){
1289                        return vContent;
1290                    }
1291                    if(_toString.call(vContent) == "[object String]"){
1292                        return '"' + vContent.replace(r, '\\"') + '"';
1293                    }
1294                    if (!vContent) return 'null';
1295                    result = '';
1296                    if (vContent.splice) {
1297                        for (i = 0, j = vContent.length; i < j; i++) result += ',' + f(vContent[i]);
1298                        return '[' + result.substr(1) + ']';
1299                    }
1300                    else {
1301                        for (i in vContent) if (vContent.hasOwnProperty(i) && vContent[i] !== undefined && typeof vContent[i] != 'function') result += ',"' + i + '":' + f(vContent[i]);
1302                        return '{' + result.substr(1) + '}';
1303                    }
1304            }
1305        };
1306    })();
1307
1308    /*
1309     function toJSON(vContent, qoute) {
1310     var type = typeof object;
1311     var isqoute = qoute;
1312     if (isqoute == undefined) isqoute = true;
1313     switch (type) {
1314     case 'undefined': return "undefined";
1315     //case 'function': return "\"" + object.toString().replace(/\"/g, "\\\"") + "\"";
1316     case 'function': return;
1317     case 'unknown': return "unknown";
1318     case 'boolean': return object.toString();
1319     case 'number': return object.toString();
1320     case 'string': return object.axtoJSON(true);
1321     }
1322     if (object === null) return 'null';
1323     if (object.axtoJSON) return object.axtoJSON(isqoute);
1324     if (isElement(object)) return;
1325     var results = [];
1326     for (var property in object) {
1327     if (object.hasOwnProperty(property)) {
1328     var value = toJSON(object[property], isqoute);
1329     if (!isUndefined(value)) results.push(property.axtoJSON(isqoute) + ':' + value);
1330     }
1331     }
1332     return '{' + results.join(', ') + '}';
1333     }
1334     */
1335
1336    /**
1337     * 오브젝트의 새로운 참조를 생성합니다.
1338     * @method Object.toJSONfn
1339     * @param {Object} object
1340     * @param {Boolean} [qoute=true] - 따옴표 표시 여부
1341     * @returns {String} JSON String
1342     */
1343    function toJSONfn(object, qoute) {
1344        var type = typeof object;
1345        var isqoute = qoute;
1346        if (isqoute == undefined) isqoute = true;
1347        switch (type) {
1348            case 'undefined':
1349                return "undefined";
1350            case 'function':
1351                try {
1352                    return toJSONfn(object(), isqoute);
1353                } catch (e) {
1354                    return;
1355                }
1356            case 'unknown':
1357                return "unknown";
1358            case 'boolean':
1359                return object.toString();
1360            case 'number':
1361                return object.toString();
1362            case 'string':
1363                return object.axtoJSON(true);
1364        }
1365        if (object === null) return 'null';
1366        if (object.axtoJSON) return object.axtoJSON(isqoute);
1367        if (isElement(object)) return;
1368        var results = [];
1369        for (var property in object) {
1370            if (object.hasOwnProperty(property)) {
1371                var value = toJSONfn(object[property], isqoute);
1372                if (!isUndefined(value)) results.push(property.axtoJSON(isqoute) + ':' + value);
1373            }
1374        }
1375        return '{' + results.join(', ') + '}';
1376    }
1377
1378    function toJSONforMobile(object) {
1379        var type = typeof object;
1380        switch (type) {
1381            case 'undefined':
1382            case 'function':
1383                return;
1384            case 'unknown':
1385                return;
1386            case 'boolean':
1387                return "\"" + object.toString() + "\"";
1388            case 'number':
1389                return "\"" + object.toString() + "\"";
1390            case 'string':
1391                return object.axtoJSON(true);
1392        }
1393        if (object === null) return 'null';
1394        if (object.toJSONforMobile) return object.toJSONforMobile(true);
1395        if (isElement(object)) return;
1396        var results = [];
1397        for (var property in object) {
1398            if (object.hasOwnProperty(property)) {
1399                var value = axtoJSON(object[property]);
1400                if (!isUndefined(value)) results.push(property.axtoJSON(true) + ':' + value);
1401            }
1402        }
1403        return '{' + results.join(', ') + '}';
1404    }
1405
1406    /**
1407     * 오브젝트의 key를 배열로 반환합니다.
1408     * @method Object.keys
1409     * @param {Object} object
1410     * @returns {Array}
1411     */
1412    function keys(obj) {
1413        var results = [];
1414        for (var property in obj) results.push(property);
1415        return results;
1416    }
1417
1418    /**
1419     * 오브젝트의 value를 배열로 반환합니다.
1420     * @method Object.values
1421     * @param {Object} object
1422     * @returns {Array}
1423     */
1424    function values(obj) {
1425        var results = [];
1426        for (var property in obj) results.push(obj[property]);
1427        return results;
1428    }
1429
1430    /**
1431     * 오브젝트의 새로운 참조를 생성합니다.
1432     * @method Object.clone
1433     * @param {Object} object
1434     * @returns {Object}
1435     */
1436    function clone(obj) { return extend({}, obj); }
1437
1438    /**
1439     * 오브젝트가 HTML 엘리먼트여부인지 판단합니다.
1440     * @method Object.isElement
1441     * @param {Object} object
1442     * @returns {Boolean}
1443     */
1444    function isElement(obj) { return !!(obj && obj.nodeType == 1); }
1445
1446    /**
1447     * 오브젝트가 Object인지 판단합니다.
1448     * @method Object.isObject
1449     * @param {Object} object
1450     * @returns {Boolean}
1451     */
1452    function isObject(obj) { return _toString.call(obj) == "[object Object]"; }
1453
1454    /**
1455     * 오브젝트가 Array인지 판단합니다.
1456     * @method Object.isArray
1457     * @param {Object} object
1458     * @returns {Boolean}
1459     */
1460    function isArray(obj) { return _toString.call(obj) == "[object Array]"; }
1461
1462    /**
1463     * 오브젝트가 Hash인지 판단합니다.
1464     * @method Object.isHash
1465     * @param {Object} object
1466     * @returns {Boolean}
1467     */
1468    function isHash(obj) { return obj instanceof Hash; }
1469
1470    /**
1471     * 오브젝트가 Function인지 판단합니다.
1472     * @method Object.isFunction
1473     * @param {Object} object
1474     * @returns {Boolean}
1475     */
1476    function isFunction(obj) { return typeof obj === "function"; }
1477
1478    /**
1479     * 오브젝트가 String인지 판단합니다.
1480     * @method Object.isString
1481     * @param {Object} object
1482     * @returns {Boolean}
1483     */
1484    function isString(obj) { return _toString.call(obj) == "[object String]"; }
1485
1486    /**
1487     * 오브젝트가 Number인지 판단합니다.
1488     * @method Object.isNumber
1489     * @param {Object} object
1490     * @returns {Boolean}
1491     */
1492    function isNumber(obj) { return _toString.call(obj) == "[object Number]"; }
1493
1494    /**
1495     * 오브젝트가 undefined인지 판단합니다.
1496     * @method Object.isUndefined
1497     * @param {Object} object
1498     * @returns {Boolean}
1499     */
1500    function isUndefined(obj) { return typeof obj === "undefined"; }
1501
1502    extend(Object, {
1503        extend: extend,
1504        inspect: inspect,
1505        toJSON: toJSON,
1506        toJSONfn: toJSONfn,
1507        toJSONforMobile: toJSONforMobile,
1508        keys: keys,
1509        values: values,
1510        clone: clone,
1511        isElement: isElement,
1512        isObject: isObject,
1513        isArray: isArray,
1514        isHash: isHash,
1515        isFunction: isFunction,
1516        isString: isString,
1517        isNumber: isNumber,
1518        isUndefined: isUndefined
1519    });
1520})();
1521
1522/**
1523 * Function.prototype
1524 * @namespace {Function} Function
1525 */
1526Object.extend(Function.prototype, (function () {
1527    var slice = Array.prototype.slice;
1528
1529    function update(array, args) {
1530        var arrayLength = array.length, length = args.length;
1531        while (length--) array[arrayLength + length] = args[length];
1532        return array;
1533    }
1534
1535    function merge(array, args) {
1536        array = slice.call(array, 0);
1537        return update(array, args);
1538    }
1539
1540    /**
1541     * @method Function.argumentNames
1542     * @returns {Array} arguments
1543     * @description 함수의 아규먼트를 배열로 반환합니다.
1544     * @example
1545     * ```js
1546     * var myFn = function(a, b, c){
1547	 *     return a;
1548	 * };
1549     *
1550     * trace(myFn.argumentNames());
1551     * //  ["a", "b", "c"]
1552     * // prototypejs 를 참조하여 제작되었습니다.
1553     * ```
1554     */
1555    function argumentNames() {
1556        var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '').replace(/\s+/g, '').split(',');
1557        return names.length == 1 && !names[0] ? [] : names;
1558    }
1559
1560    /**
1561     * @method Function.bind
1562     * @param {Object} bindTarget
1563     * @param {Object} [Argument]
1564     * @description 함수의 위치를 bind 대상에 연결하여 줍니다.
1565     * @example
1566     * ```js
1567     * var AlertClass = Class.create({
1568	 *     initialize: function(msg) {
1569	 *        this.msg = msg;
1570	 *    },
1571	 *    handleClick: function(event) {
1572	 *        alert(this.msg);
1573	 *    }
1574	 * });
1575     * var myalert = new AlertClass("AXJ Clicked");
1576     *
1577     * $("#link1").click(myalert.handleClick);
1578     * //undefined
1579     * $("#link2").click(myalert.handleClick.bind(myalert));
1580     * //AXJ Clicked
1581     *
1582     * // ---------------------
1583     * var AlertClass = Class.create({
1584	 *    initialize: function(msg) {
1585	 *        this.msg = msg;
1586	 *    },
1587	 *    handleClick: function(a, b, c, event) {
1588	 *        trace({a:a, b:b, c:c, event:event.type});
1589	 *        // {"a":"A", "b":"X", "c":"J", "event":"click"}
1590	 *        alert(this.msg);
1591	 *    }
1592	 * });
1593     * var myalert = new AlertClass("AXJ Clicked");
1594     *
1595     * $("#link1").click(myalert.handleClick);
1596     * $("#link2").click(myalert.handleClick.bind(myalert, "A", "X", "J"));
1597     * ```
1598     */
1599    function bind(context) {
1600        if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
1601        var __method = this, args = slice.call(arguments, 1);
1602        return function () {
1603            var a = merge(args, arguments);
1604            return __method.apply(context, a);
1605        }
1606    }
1607
1608    function curry() {
1609        if (!arguments.length) return this;
1610        var __method = this, args = slice.call(arguments, 0);
1611        return function () {
1612            var a = merge(args, arguments);
1613            return __method.apply(this, a);
1614        }
1615    }
1616
1617    /**
1618     * @method Function.delay
1619     * @param {Number} timeout - second
1620     * @description 함수의 실행을 지정된 시간 후에 실행되게 합니다.
1621     * @example
1622     * ```js
1623     * var showMsg = function(a, b){
1624	 *     alert(a+"/"+b);
1625	 * };
1626     * showMsg.delay(2, "AX", "ISJ");
1627     * // 2초 후에 alert 구문이 실행됩니다.
1628     * // 내부네서 this.apply 를 호출합니다. 간단한 함수 호출에는 사용을 권장하지만 복잡한 형태의 함수 구현에는 권장하지 않습니다.
1629     * ```
1630     */
1631    function delay(timeout) {
1632        var __method = this, args = slice.call(arguments, 1);
1633        timeout = timeout * 1000;
1634        return window.setTimeout(function () { return __method.apply(__method, args); }, timeout);
1635    }
1636
1637    function defer() {
1638        var args = update([0.01], arguments);
1639        return this.delay.apply(this, args);
1640    }
1641
1642    function wrap(wrapper) {
1643        var __method = this;
1644        return function () {
1645            var a = update([__method.bind(this)], arguments);
1646            return wrapper.apply(this, a);
1647        }
1648    }
1649
1650    function methodize() {
1651        if (this._methodized) return this._methodized;
1652        var __method = this;
1653        return this._methodized = function () {
1654            var a = update([this], arguments);
1655            return __method.apply(null, a);
1656        };
1657    }
1658
1659    function addPrototype(fns) {
1660        var name, i = 0, length = fns.length, isObj = length === undefined || Object.isFunction(fns);
1661        if (isObj) {
1662            for (name in fns) {
1663                this.prototype[name] = fns[name];
1664            }
1665        }
1666    }
1667
1668    return {argumentNames: argumentNames, bind: bind, curry: curry, delay: delay, defer: defer, wrap: wrap, methodize: methodize, addPrototype: addPrototype}
1669})());
1670
1671/**
1672 * String.prototype
1673 * @namespace {String} String
1674 */
1675Object.extend(String.prototype, (function () {
1676    function password() { return Math.tan(45).toString().substr(7)}
1677
1678    /**
1679     * 문자열 시작부터 지정한 글자수 만큼 반환합니다.
1680     * @method String.left
1681     * @param {Number} strLen
1682     * @returns {String}
1683     * @example
1684     * ```js
1685     * "AXJ_String".left(3); -> "AXJ"
1686     * toast.push('left(3) : ' + "AXJ_String".left(3));
1687     * ```
1688     */
1689    function left(strLen) { return this.toString().substr(0, strLen); }
1690
1691    /**
1692     * 문자열 끝부터 지정한 글자수 만큼 반환합니다.
1693     * @method String.right
1694     * @param {Number} strLen
1695     * @returns {String}
1696     * @example
1697     * ```js
1698     * "AXJ_String".right(3); -> "ing"
1699     * toast.push('right(3) : '+$('#AXJrightTest').val().left(3));
1700     * ```
1701     */
1702    function right(strLen) { return this.substring(this.length - strLen, this.length); }
1703
1704    /**
1705     * URLencode된 문자열을 디코드 합니다.
1706     * @method String.dec
1707     * @returns {String}
1708     * @example
1709     * ```js
1710     * "AXJ_String%2C%EC%97%91%EC%8B%9C%EC%8A%A4%EC%A0%9C%EC%9D%B4".dec(); -> "AXJ_String,엑시스제이"
1711     * ```
1712     */
1713    function dec() {
1714        var decodeURI;
1715        try {
1716            decodeURI = decodeURIComponent(this);
1717        }
1718        catch (e) {
1719            decodeURI = unescape(this);
1720        }
1721        return decodeURI;
1722        /*
1723         var decodeURI;
1724         try{decodeURI = decodeURIComponent(this.replace(/\+/g, " "));}catch(e){var decodeURI = this;}
1725         return (this) ? (decodeURI) : this;
1726         */
1727    }
1728
1729    /**
1730     * URLencode된 문자열로 인코드 합니다.
1731     * @method String.enc
1732     * @returns {String}
1733     * @example
1734     * ```js
1735     * "AXJ_String,엑시스제이".enc(); -> "AXJ_String%2C%EC%97%91%EC%8B%9C%EC%8A%A4%EC%A0%9C%EC%9D%B4"
1736     * ```
1737     */
1738    function enc() { return (this) ? encodeURIComponent(this) : this; }
1739
1740    /**
1741     * JSONString이면 Object로 변환합니다.
1742     * @method String.object
1743     * @returns {Object}
1744     * @example
1745     * ```js
1746     * var myObj = "{a:1, b:2, name:'AXJ'}".object();
1747     * trace(myObj);
1748     * // {"a":1, "b":2, "name":"AXJ"}
1749     *
1750     * var myObjError = "{1, b:2, name:'AXJ'}".object();
1751     * trace(myObjError);
1752     * // {"error":"syntaxerr", "result":"syntaxerr", "msg":"JSON syntax error.�{1, b:2, name:'AXJ'}", "body":"{1, b:2, name:'AXJ'}"}
1753     * ```
1754     */
1755    function object() {
1756        try {
1757            var res = this.evalJSON();
1758        } catch (e) {
1759            res = {error: "syntaxerr", result: "syntaxerr", msg: "to object error, " + e.print() + ", " + this};
1760            try {
1761                mask.close();
1762            } catch (e) {
1763            }
1764        }
1765        return res;
1766    }
1767
1768    /**
1769     * 콤마가 포함된 문자열을 Array로 변환합니다.
1770     * @method String.array
1771     * @returns {Array}
1772     * @example
1773     * ```js
1774     * var myObj = "a,b,c".array();
1775     * trace(myObj);
1776     * // ["a", "b", "c"]
1777     * ```
1778     */
1779    function array() {
1780        try {
1781            var res = this.split(/,/g);
1782        } catch (e) {
1783            res = {error: "syntaxerr", result: "syntaxerr", msg: "to object error, " + e.print() + ", " + this};
1784        }
1785        return res;
1786    }
1787
1788    /**
1789     * 문자열을 date 형식에 맞추어 날짜 포멧으로 리턴합니다.
1790     * @method String.date
1791     * @param {String} [separator=-] 날짜구분자
1792     * @returns {Date}
1793     * @example
1794     * ```js
1795     * trace("20121119".date());
1796     * // "2012-11-19T03:00:00Z"
1797     *
1798     * trace("2012-11-19".date());
1799     * // "2012-11-19T03:00:00Z"
1800     *
1801     * trace("2012/11/19".date("/"));
1802     * // "2012-11-19T03:00:00Z"
1803     * ```
1804     */
1805    function toDate(separator, defaultDate) {
1806        function local_date(yy, mm, dd, hh, mi, ss) {
1807            var utc_d, local_d;
1808            local_d = new Date();
1809            if (typeof hh === "undefined") hh = 23;
1810            if (typeof mi === "undefined") mi = 59;
1811            utc_d = new Date(Date.UTC(yy, mm, dd || 1, hh, mi, ss || 0));
1812
1813            if (mm == 0 && dd == 1 && utc_d.getUTCHours() + (utc_d.getTimezoneOffset() / 60) < 0) {
1814                utc_d.setUTCHours(0);
1815            }
1816            else {
1817                utc_d.setUTCHours(utc_d.getUTCHours() + (utc_d.getTimezoneOffset() / 60));
1818            }
1819            return utc_d;
1820        }
1821
1822        if (this.length == 0) {
1823            return defaultDate || new Date();
1824        }
1825        else if (this.length > 15) {
1826            var yy, mm, dd, hh, mi,
1827                aDateTime = this.split(/ /g), aTimes, aTime,
1828                aDate = aDateTime[0].split(separator || "-"),
1829                utc_d, local_d;
1830
1831            yy = aDate[0];
1832            mm = parseFloat(aDate[1]);
1833            dd = parseFloat(aDate[2]);
1834            aTime = aDateTime[1] || "09:00";
1835            aTimes = aTime.left(5).split(":");
1836            hh = parseFloat(aTimes[0]);
1837            mi = parseFloat(aTimes[1]);
1838            if (aTime.right(2) === "AM" || aTime.right(2) === "PM") hh += 12;
1839            return local_date(yy, mm - 1, dd, hh, mi);
1840        }
1841        else if (this.length == 14) {
1842            var va = this.replace(/\D/g, "");
1843            return local_date(va.substr(0, 4), va.substr(4, 2).number() - 1, va.substr(6, 2).number(), va.substr(8, 2).number(), va.substr(10, 2).number(), va.substr(12, 2).number());
1844        }
1845        else if (this.length > 7) {
1846            var va = this.replace(/\D/g, "");
1847            return local_date(va.substr(0, 4), va.substr(4, 2).number() - 1, va.substr(6, 2).number());
1848        }
1849        else if (this.length > 4) {
1850            var va = this.replace(/\D/g, "");
1851            return local_date(va.substr(0, 4), va.substr(4, 2).number() - 1, 1);
1852        }
1853        else if (this.length > 2) {
1854            var va = this.replace(/\D/g, "");
1855            return local_date(va.substr(0, 4), va.substr(4, 2).number() - 1, 1);
1856        }
1857        else {
1858            return defaultDate || new Date();
1859        }
1860    }
1861
1862    /**
1863     * 문자열을 Number로 변환해 줍니다.
1864     * @method String.number
1865     * @returns {Number}
1866     * @example
1867     * ```js
1868     * var str = "1234";
1869     * trace(typeof str);
1870     * // string
1871     *
1872     * str = str.number();
1873     * trace(typeof str);
1874     * // number
1875     *
1876     * "1,234".number(); -> 1234
1877     * "1,234.1".number(); -> 1234.1
1878     * ```
1879     */
1880    function toNum() {
1881        var pair = this.replace(/,/g, "").split(".");
1882        var isMinus = false;
1883        if (parseFloat(pair[0]) < 0) isMinus = true;
1884        if (pair[0] == "-0") isMinus = true;
1885        var returnValue = 0.0;
1886        pair[0] = pair[0].replace(/[-|+]?[\D]/gi, "");
1887        if (pair[1]) {
1888            pair[1] = pair[1].replace(/\D/gi, "");
1889            returnValue = parseFloat(pair[0] + "." + pair[1]) || 0;
1890        }
1891        else {
1892            returnValue = parseFloat(pair[0]) || 0;
1893        }
1894        return (isMinus) ? -returnValue : returnValue;
1895    }
1896
1897    function parseF() { return parseFloat(this); }
1898
1899    /**
1900     * 문자열의 앞뒤 공백을 제거하여 줍니다.
1901     * @method String.trim
1902     * @returns {String}
1903     * @example
1904     * ```js
1905     * " AXJ ".trim(); ->  "AXJ"
1906     * ```
1907     */
1908    function strip() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); }
1909
1910    /**
1911     * 문자열에서 HTML 태그를 제거하여 반환합니다.
1912     * @method String.delHtml
1913     * @returns {String}
1914     * @example
1915     * ```js
1916     * "<div>AXJ</div>".delHtml(); ->  "AXJ"
1917     * ```
1918     */
1919    function stripTags() { return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); }
1920
1921    /**
1922     * 문자열에서 Script 태그를 제거하여 반환합니다.
1923     * @method String.delScript
1924     * @returns {String}
1925     * @example
1926     * ```js
1927     * "<script src="scriptname"></script>AXJ".delScript(); ->  "AXJ"
1928     * ```
1929     */
1930    function stripScript() {
1931        //스크립트 제거
1932        var cStr;
1933        var RegExpJS = new RegExp("<[ ]*script[^>]*>[^<]*</[ ]*script[^>]*>", "gi");
1934        cStr = this.replace(RegExpJS, "");
1935
1936        cStr = cStr.replace(/[\s]*onclick[^=]*=/gi, " xonclick=");
1937        cStr = cStr.replace(/[\s]*onmouserover[^=]*=/gi, " xonmouseover=");
1938        cStr = cStr.replace(/[\s]*onmouseout[^=]*=/gi, " xonmouseout=");
1939        cStr = cStr.replace(/[\s]*onchange[^=]*=/gi, " xonchange=");
1940        cStr = cStr.replace(/[\s]*onblur[^=]*=/gi, " xonblur=");
1941        cStr = cStr.replace(/[\s]*onerror[^=]*=/gi, " xonerror=");
1942        cStr = cStr.replace(/[\s]*onload[^=]*=/gi, " xonload=");
1943        cStr = cStr.replace(/[\s]*href[^=]*=[\s]*["']?javascript/gi, " href=\"xjavascript");
1944
1945        return cStr;
1946    }
1947
1948    /**
1949     * 문자열을 반복하여 반환합니다.
1950     * @method String.times
1951     * @param {Number} count
1952     * @returns {String}
1953     * @example
1954     * ```js
1955     * "AXJ".times(3); ->  "AXJAXJAXJ"
1956     * ```
1957     */
1958    function times(count) { return count < 1 ? '' : new Array(count + 1).join(this); }
1959
1960    function inspect(useDoubleQuotes) {
1961        var escapedString = this.replace(
1962            /[\x00-\x1f\\]/g,
1963            function (character) {
1964                try {
1965                    if (character in String.specialChar) return String.specialChar[character];
1966                } catch (e) {
1967                }
1968                if (character.charCodeAt() == 13) return "\\r";
1969                if (character.charCodeAt() == 10) return "\\n";
1970                return '\\u00' + character.charCodeAt()
1971            }
1972        );
1973        if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
1974        return "" + escapedString.replace(/'/g, '\\\'') + "";
1975    }
1976
1977    function axtoJSON(TF) {
1978        return this.inspect(TF || false);
1979    }
1980
1981    function blank() { return /^\s*$/.test(this); }
1982
1983    function isJSON() {
1984        var str = this;
1985        if (str.isBlank()) return false;
1986        str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
1987        return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
1988    } //"
1989    function unfilterJSON(filter) { return this.replace(filter || AXUtil.JSONFilter, '$1'); }
1990
1991    function evalJSON(sanitize) {
1992        var json = this.unfilterJSON();
1993        try {
1994            var _evl = eval;
1995            if (!sanitize || json.isJSON()) return _evl("(" + json + ")");
1996            else return {error: "syntaxerr", result: "syntaxerr", msg: "JSON syntax error. fail to convert Object\n" + this};
1997            _evl = null;
1998        } catch (e) {
1999            return {
2000                error: e,
2001                result: "syntaxerr",
2002                msg: e,
2003                body: this
2004            };
2005        }
2006    }
2007
2008    /**
2009     * queryString 형식의 문자열을 json object로 변환하여 줍니다.
2010     * @method String.queryToObject
2011     * @param {String} [separator=&]
2012     * @returns {Object}
2013     * @example
2014     * ```js
2015     * var myObject = "a=1&b=1".queryToObject();
2016     * trace(myObject);
2017     * // {"a":"1", "b":"1"}
2018     * ```
2019     */
2020    function queryToObject(separator) {
2021        var match = this.trim().match(/([^?#]*)(#.*)?$/);
2022        if (!match) return {};
2023        var rs = match[1].split(separator || '&');
2024        var returnObj = {};
2025        var i = 0;
2026        while (i < rs.length) {
2027            var pair = rs[i].split("=");
2028            var k = pair[0], v = pair[1];
2029            if (returnObj[k] != undefined) {
2030                if (!Object.isArray(returnObj[k])) returnObj[k] = [returnObj[k]];
2031                returnObj[k].push(v);
2032            }
2033            else {
2034                returnObj[k] = v;
2035            }
2036            i++;
2037        }
2038        return returnObj;
2039    }
2040
2041    /**
2042     * queryString 형식의 문자열을 json object로 변환하여 줍니다. (파라미터 값
2042은 URLDecode 합니다.)
2043     * @method String.queryToObjectDec
2044     * @param {String} [separator=&]
2045     * @returns {Object}
2046     * @example
2047     * ```js
2048     * var myObject = "a=1&b=1".queryToObject();
2049     * trace(myObject);
2050     * // {"a":"1", "b":"1"}
2051     * ```
2052     */
2053    function queryToObjectDec(separator) {
2054        var match = this.trim().match(/([^?#]*)(#.*)?$/);
2055        if (!match) return {};
2056        var rs = match[1].split(separator || '&');
2057        var returnObj = {};
2058        var i = 0;
2059        while (i < rs.length) {
2060            var pair = rs[i].split("=");
2061            var k = pair[0], v = pair[1];
2062            if (returnObj[k] != undefined) {
2063                if (!Object.isArray(returnObj[k])) returnObj[k] = [returnObj[k]];
2064                returnObj[k].push(v.dec());
2065            }
2066            else {
2067                returnObj[k] = v.dec();
2068            }
2069            i++;
2070        }
2071        return returnObj;
2072    }
2073
2074    /**
2075     * 줄넘김 문자열 '\n'을 &gt;br/> 태그로 변환하여 줍니다.
2076     * @method String.crlf
2077     * @param {Regexp} [replaceTarget=/\n/g]
2078     * @param {String} [replacer=&gt;br/>]
2079     * @returns {String}
2080     * @example
2081     * ```js
2082     * "123
2083     * 123".crlf(); ->  "123<br/>123"
2084     * ```
2085     */
2086    function crlf(replaceTarget, replacer) { return this.replace((replaceTarget || /\n/g), (replacer || "<br/>")); }
2087
2088    /**
2089     * 줄넘김 문자열 '%0A'을 &gt;br/> 태그로 변환하여 줍니다.
2090     * @method String.ecrlf
2091     * @param {Regexp} [replaceTarget=/%0A/g]
2092     * @param {String} [replacer=&gt;br/>]
2093     * @returns {String}
2094     * @example
2095     * ```js
2096     * "123%0A123".crlf(); ->  "123<br/>123"
2097     * ```
2098     */
2099    function ecrlf(replaceTarget, replacer) { return this.replace((replaceTarget || /%0A/g), (replacer || "<br/>")); }
2100
2101    /**
2102     * 문자열 자리수를 맞추어 줍니다.
2103     * @method String.setDigit
2104     * @param {Number} length
2105     * @param {String} [padder=0]
2106     * @returns {String}
2107     * @example
2108     * ```js
2109     * "A".setDigit(3); ->  "00A"
2110     * "A".setDigit(3, '!'); ->  "!!A"
2111     * ```
2112     */
2113    function formatDigit(length, padder) {
2114        var string = this;
2115        return (padder || '0').times(length - string.length) + string;
2116    }
2117
2118    /**
2119     * 파일경로에서 파일명을 반환합니다.
2120     * @method String.getFileName
2121     * @returns {String}
2122     * @example
2123     * ```js
2124     *"C://Works/AXISJ_project/css/myfile.zip".getFileName(); ->  "myfile.zip"
2125     * ```
2126     */
2127    function getFileName() {
2128        var sToMatch = this;
2129        var reAt = /[\/\\]?([^\/\\]?\.?[^\/\\]+)$/;
2130        var reArr = sToMatch.match(reAt);
2131        return RegExp.$1;
2132    }
2133
2134    /**
2135     * Mozila 브라우저 등에서 사용하는 색상정보 값을 표준색상코드로 변환합니다. 표준색상코드를 입력하여도 표준색상코드 값을 얻을 수 있습니다.
2136     * @method String.toColor
2137     * @param {String} [prefix]
2138     * @returns {String}
2139     * @example
2140     * ```js
2141     * "rgb(243, 243, 243)".toColor(); ->  "f3f3f3"
2142     * "rgb(243, 243, 243)".toColor('#'); ->  "#f3f3f3"
2143     * "#f3f3f3".toColor(); ->  "f3f3f3"
2144     * "f3f3f3".toColor(); ->  "f3f3f3"
2145     * "f3f3f3".toColor('#'); ->  "#f3f3f3"
2146     * ```
2147     */
2148    function toColor(sharp) {
2149        var colorValue = "";
2150        if (this.left(3) == "rgb") {
2151            var val = this;
2152            var reAt = /rgb\((.+)\)/;
2153            val.match(reAt);
2154            var vals = RegExp.$1.split(", ");
2155            for (var a = 0; a < vals.length; a++) {
2156                vals[a] = vals[a].number().setDigit(2, '0', 16);
2157            }
2158            colorValue = vals.join("");
2159        }
2160        else {
2161            colorValue = this.replace("#", "");
2162        }
2163        var preFix = (sharp) ? "#" : "";
2164        return preFix + colorValue;
2165    }
2166
2167    /**
2168     * 숫자형 문자열에 콤마를 삽입하여 통화단위로 반환합니다.
2169     * @method String.money
2170     * @returns {String}
2171     * @example
2172     * ```js
2173     * "1000000".money()
2174     * // "1,000,000"
2175     * ```
2176     */
2177    function toMoney() { return this.number().money(); }
2178
2179    function toByte() { return this.number().byte(); }
2180
2181    /**
2182     * 문자열을 소문자로 반환합니다.
2183     * @method String.lcase
2184     * @returns {String}
2185     * @example
2186     * ```js
2187     * "AXISJ".lcase() -> "axisj"
2188     * ```
2189     */
2190    function lcase() { return this.toLowerCase(); }
2191
2192    /**
2193     * 문자열을 대문자로 반환합니다.
2194     * @method String.ucase
2195     * @returns {String}
2196     * @example
2197     * ```
2198     * "axisj".ucase() -> "AXISJ"
2199     * ```
2200     */
2201    function ucase() { return this.toUpperCase(); }
2202
2203    /**
2204     * 문자열의 바이트 값을 계산하여 줍니다.
2205     * @method String.getByte
2206     * @returns {Number}
2207     * @example
2208     * ```
2209     * trace("장".getByte());
2210     * // 2
2211     * trace("a".getByte());
2212     * // 1
2213     * ```
2214     */
2215    function getByte() {
2216        var valueByte = this.length;
2217        for (i = 0, l = this.length; i < l; i++) if (this.charCodeAt(i) > 128) valueByte++;
2218        return valueByte;
2219    }
2220
2221    /**
2222     * 문자열을 전화번호 형태로 반홥니다.
2223     * @method String.phone
2224     * @returns {String}
2225     * @example
2226     * ```js
2227     * trace("장".phone());
2228     * // 02
2229     * trace("a".phone());
2230     * // 02
2231     * trace("88819123".phone());
2232     * // 02-8881-9123
2233     * trace("01088819123".phone());
2234     * // 010-8881-9137
2235     * ```
2236     */
2237    function toPhoneString() {
2238        if (this == "") return this;
2239        var _this = this.replace(/\D+/g, "");
2240        var myLocalNums = "";
2241        var num1 = "", num2 = "";
2242        var localNum = "031/032/033/041/042/043/051/052/053/054/055/061/062/063/064/010/011/016/017/019/070/080/060";
2243        if (_this.left(2) == "02") {
2244            myLocalNums = "02";
2245        }
2246        else {
2247            var localNums = localNum.split(/\//g);
2248            var tempNum = _this.left(3);
2249            AXUtil.each(localNums, function () {
2250                if (this == tempNum) {
2251                    myLocalNums = this;
2252                    return false;
2253                }
2254            });
2255        }
2256
2257        if (myLocalNums == "") {
2258            myLocalNums = "02";
2259            if (_this.length > 7) {
2260                num1 = _this.substr(0, 4);
2261                num2 = _this.substr(4);
2262            }
2263            else {
2264                num1 = _this.substr(0, 3);
2265                num2 = _this.substr(3);
2266            }
2267        }
2268        else {
2269            try {
2270                var snum = myLocalNums.length;
2271                if ((_this.length - snum) > 7) {
2272                    num1 = _this.substr(snum, 4);
2273                    num2 = _this.substr(snum + 4);
2274                }
2275                else {
2276                    num1 = _this.substr(snum, 3);
2277                    num2 = _this.substr(snum + 3);
2278                }
2279            } catch (e) {
2280                //trace(e);
2281            }
2282        }
2283
2284        var returnString = myLocalNums;
2285        if (num1 != "") returnString += "-" + num1;
2286        if (num2 != "") returnString += "-" + num2;
2287
2288        return returnString;
2289
2290    }
2291
2292    /**
2293     * anchor 데이터를 반환합니다.
2294     * @method String.getAnchorData
2295     * @returns {String}
2296     * @example
2297     * ```js
2298     * "http://jdoc.axisj.com/#{id:\"/API/Prototype/String/phone\"}".getAnchorData();
2299     * "{id:"/API/Prototype/String/phone"}"
2300     * ```
2301     */
2302    function getAnchorData() {
2303        var idx = this.indexOf("#", 0);
2304        if (idx < 0) return "";
2305        var cnt = this.length;
2306        var str = this.substring(idx + 1, cnt);
2307        return str;
2308    }
2309
2310    function print() {
2311        return this;
2312    }
2313
2314    return {
2315        ppassword: password,
2316        left: left,
2317        right: right,
2318        dec: dec,
2319        decode: dec,
2320        enc: enc,
2321        object: object,
2322        array: array,
2323        date: toDate,
2324        number: toNum,
2325        num: parseF,
2326        money: toMoney,
2327        byte: toByte,
2328        trim: strip,
2329        delHtml: stripTags,
2330        delScript: stripScript,
2331        removeScript: stripScript,
2332        times: times,
2333        inspect: inspect,
2334        axtoJSON: axtoJSON,
2335        isBlank: blank,
2336        isJSON: isJSON,
2337        unfilterJSON: unfilterJSON,
2338        evalJSON: evalJSON,
2339        queryToObject: queryToObject,
2340        queryToObjectDec: queryToObjectDec,
2341        crlf: crlf,
2342        ecrlf: ecrlf,
2343        setDigit: formatDigit,
2344        getFileName: getFileName,
2345        toColor: toColor,
2346        lcase: lcase,
2347        ucase: ucase,
2348        getByte: getByte,
2349        phone: toPhoneString,
2350        getAnchorData: getAnchorData,
2351        print: print
2352    }
2353})());
2354
2355/**
2356 * Number.prototype
2357 * @namespace {Number} Number
2358 */
2359Object.extend(Number.prototype, (function () {
2360    /**
2361     * 숫자를 문자열로 변환하고 시작부터 지정한 글자수 만큼 반환합니다.
2362     * @method Number.left
2363     * @param {Number} strLen
2364     * @returns {String}
2365     * @example
2366     * ```js
2367     * (1234).left(3); -> "123"
2368     * ```
2369     */
2370    function left(strLen) { return this.toString().substr(0, strLen); }
2371
2372    /**
2373     * 숫자를 문자열로 변환하고 마지막부터 지정한 글자수 만큼 반환합니다.
2374     * @method Number.right
2375     * @param {Number} strLen
2376     * @returns {String}
2377     * @example
2378     * ```js
2379     * 1234.right(3); -> 234
2380     * ```
2381     */
2382    function right(strLen) { return this.toString().substring(this.toString().length - strLen, this.toString().length); }
2383
2384    /**
2385     * 통화표현 단위로 변환된 문자열을 반환합니다.
2386     * @method Number.money
2387     * @returns {String}
2388     * @example
2389     * ```js
2390     * trace((1234.9).money());
2391     * //1,234.9
2392     * trace((1234.1).money());
2393     * //1,234.1
2394     * trace((-1234.9).money());
2395     * //-1,234.9
2396     * trace((-1234.1).money());
2397     * //-1,234.1
2398     *
2399     * (12345678).money(); -> "12,345,678"
2400     * "12345678".money(); -> "12,345,678"
2401     * // String 에서도 money 메소드를 직접 사용 할 수 있습니다.
2402     * ```
2403     */
2404    function toMoney() {
2405        var txtNumber = '' + this;
2406        if (isNaN(txtNumber) || txtNumber == "") {
2407            return "";
2408        }
2409        else {
2410            var rxSplit = new RegExp('([0-9])([0-9][0-9][0-9][,.])');
2411            var arrNumber = txtNumber.split('.');
2412            arrNumber[0] += '.';
2413            do {
2414                arrNumber[0] = arrNumber[0].replace(rxSplit, '$1,$2');
2415            } while (rxSplit.test(arrNumber[0]));
2416            if (arrNumber.length > 1) {
2417                return arrNumber.join('');
2418            }
2419            else {
2420                return arrNumber[0].split('.')[0];
2421            }
2422        }
2423    }
2424
2425    /**
2426     * 숫자값을 Byte로 인식하여 값에 크기에 따르 KB, MB, GB 의 형식으로 반환합니다.
2427     * @method Number.byte
2428     * @returns {String}
2429     * @example
2430     * ```js
2431     * trace((1234567890).byte());
2432     * // 1.1GB
2433     * trace((12345678).byte());
2434     * // 11.8MB
2435     * trace((123456).byte());
2436     * // 120.6KB
2437     * trace((123).byte());
2438     * // 0.1KB
2439     * ```
2440     */
2441    function toByte() {
2442        var n_unit = "KB";
2443        var myByte = this / 1024;
2444        if (myByte / 1024 > 1) {
2445            n_unit = "MB";
2446            myByte = myByte / 1024;
2447        }
2448        if (myByte / 1024 > 1) {
2449            n_unit = "GB";
2450            myByte = myByte / 1024;
2451        }
2452        return myByte.round(1) + n_unit;
2453    }
2454
2455    /**
2456     * 자신을 반환합니다.
2457     * @method Number.number
2458     * @returns {Number}
2459     */
2460    function toNum() { return this; }
2461
2462    /**
2463     * 원하는 횟수 만큼 자릿수 맞춤 문자열을 포함한 문자열을 반환합니다.
2464     * @method Number.setDigit
2465     * @param {Number} length - 자릿수
2466     * @param {String} padder - 자릿수 맞춤 문자열
2467     * @param {Number} radix - 진수
2468     * @returns {String}
2469     * @example
2470     * ```js
2471     * trace( (11).setDigit(3) );
2472     * //011
2473     * trace( (11).setDigit(3, '!') );
2474     * //!11
2475     * trace( (11).setDigit(3, 0, 16) );
2476     * //00b
2477     * trace( (25).setDigit(5, "X", 8) );
2478     * //XXX31
2479     * ```
2480     */
2481    function formatDigit(length, padder, radix) {
2482        var string = this.toString(radix || 10);
2483        return (padder || '0').times(length - string.length) + string;
2484    }
2485
2486    /**
2487     * 인자값부터 원본까지 정수 단위로 이어진 배열을 리턴합니다.
2488     * @method Number.rangeFrom
2489     * @param {Number} start - 배열시작위치
2490     * @returns {Array}
2491     * @example
2492     * ```js
2493     * (3).rangeFrom(0);
2494     * [0, 1, 2, 3]
2495     * ```
2496     */
2497    function range(start) {
2498        var ra = [];
2499        for (var a = (start || 0); a < this + 1; a++) ra.push(a);
2500        return ra;
2501    }
2502
2503    function axtoJSON() { return this; }
2504
2505    /**
2506     * 절대값을 반환합니다.
2507     * @method Number.abs
2508     * @returns {Number}
2509     * @example
2510     * ```js
2511     * trace((1234).abs());
2512     * // 1234
2513     * trace((-1234).abs());
2514     * // 1234
2515     * trace((1234.123).abs());
2516     * // 1234.123
2517     * trace((-1234.123).abs());
2518     * // 1234.123
2519     * ```
2520     */
2521    function abs() { return Math.abs(this); }
2522
2523    /**
2524     * 반올림 위치에서부터 반올림 한 값을 반환합니다.
2525     * @method Number.round
2526     * @param {Number} digit
2527     * @returns {Number}
2528     * @example
2529     * ```js
2530     * trace((1234.5678).round());
2531     * //1235
2532     * trace((1234.5678).round(1));
2533     * //1234.6
2534     * trace((1234.5678).round(2));
2535     * //1234.57
2536     * ```
2537     */
2538    function round(digit) {
2539        return (typeof digit == "undefined") ? Math.round(this) :
2540            (this.toString().search('e-')) ? this.toFixed(digit) : +(Math.round(this + "e+" + digit) + "e-" + digit);
2541    }
2542
2543    /**
2544     * Math.ceil
2545     * @method Number.ceil
2546     * @returns {Number}
2547     */
2548    function ceil() { return Math.ceil(this); }
2549
2550    /**
2551     * Math.floor
2552     * @method Number.floor
2553     * @returns {Number}
2554     */
2555    function floor() { return Math.floor(this); }
2556
2557    /**
2558     * 숫자를 time값으로 이용하여 Date를 반환합니다.
2559     * @method Number.date
2560     * @returns {Date}
2561     * @example
2562     * ```js
2563     * var ndate = new Date();
2564     * ndate.getTime();
2565     * // 1417253161813
2566     * (1417253161813).date();
2567     * // Sat Nov 29 2014 18:26:01 GMT+0900 (KST)
2568     * ```
2569     */
2570    function date() { return new Date(this); }
2571
2572    /**
2573     * 나누기 연산 결과를 반환합니다. divisor 가 0인 경우 연산 결과는 오류 없이 0을 반환합니다.
2574     * @method Number.div
2575     * @param {Number} divisor - 나눔수
2576     * @returns {Number}
2577     * @example
2578     * ```js
2579     * trace( (10).div(2); );
2580     * // 5
2581     * trace( (10).div(0); );
2582     * // 0
2583     * ```
2584     */
2585    function div(divisor) {
2586        if (divisor != 0) {
2587            return this / divisor;
2588        }
2589        else {
2590            return 0;
2591        }
2592    }
2593
2594    function none() { return this; }
2595
2596    function times(count) { return count < 1 ? '' : new Array(count + 1).join(this.toString()); }
2597
2598    /**
2599     * 숫자를 문자로 변환후 String.phone를 실행합니다.
2600     * @method Number.phone
2601     * @returns {String}
2602     */
2603    function phone() {
2604        var txtNumber = '' + this;
2605        return txtNumber.phone();
2606    }
2607
2608    return {
2609        left: left,
2610        right: right,
2611        abs: abs,
2612        round: round,
2613        ceil: ceil,
2614        floor: floor,
2615        money: toMoney,
2616        byte: toByte,
2617        num: toNum,
2618        number: toNum,
2619        setDigit: formatDigit,
2620        date: date,
2621        div: div,
2622        dec: none,
2623        enc: none,
2624        rangeFrom: range,
2625        axtoJSON: axtoJSON,
2626        times: times,
2627        phone: phone
2628    }
2629})());
2630
2631/**
2632 * Date.prototype
2633 * @namespace {Date} Date
2634 */
2635Object.extend(Date.prototype, (function () {
2636    /**
2637     * @method Data.add
2638     * @param {Number} daunum
2639     * @param {String} [interval=d] - y|m|d
2640     * @returns {Date}
2641     * @description 원본날짜에서 인자만큼 더해진 날짜 데이터를 반환합니다.
2642     * @example
2643     * ```js
2644     * var myDate = new Date();
2645     * trace(myDate.add(1));
2646     * // 내일값이 나옵니다.
2647     *
2648     * trace("2013-05-05".date().add(3));
2649     * // "2013-05-08T03:00:00Z"
2650     * trace("2013-05-05".date().add(2, 'm'));
2651     * //  "2013-07-05T03:00:00Z"
2652     * trace("2013-05-05".date().add(2, 'y'));
2653     * //  "2015-05-05T03:00:00Z"
2654     * ```
2655     */
2656    function dateAdd(daynum, interval) {
2657        interval = interval || "d";
2658        var interval = interval.toLowerCase();
2659        var DyMilli = ((1000 * 60) * 60) * 24;
2660        var aDate = new Date(this.getUTCFullYear(), this.getMonth(), this.getDate(), 12);
2661
2662        if (interval == "d") {
2663            //trace(aDate.getTime(), (daynum) , (DyMilli));
2664            aDate.setTime(aDate.getTime() + (daynum * DyMilli));
2665        }
2666        else if (interval == "m") {
2667            var yy = aDate.getFullYear();
2668            var mm = aDate.getMonth();
2669            var dd = aDate.getDate();
2670            /*if (mm == 0 && dd == 1) yy += 1;*/
2671            yy = yy + parseInt(daynum / 12);
2672            mm += daynum % 12;
2673            var mxdd = AXUtil.dayLen(yy, mm);
2674            if (mxdd < dd) dd = mxdd;
2675            aDate = new Date(yy, mm, dd, 12);
2676        }
2677        else if (interval == "y") {
2678            aDate.setTime(aDate.getTime() + ((daynum * 365) * DyMilli));
2679        }
2680        else {
2681            aDate.setTime(aDate.getTime() + (daynum * DyMilli));
2682        }
2683        return aDate;
2684    }
2685
2686    /**
2687     * @method Data.diff
2688     * @param {Date|String} edDate
2689     * @param {String} [type=d] - y|m|d
2690     * @returns {Number}
2691     * @description 날짜와 날짜 사이의 날짜 수를 반환합니다.
2692     * @example
2693     * ```js
2694     * trace( "2013-05-05".date().diff("2013-05-08") );
2695     * // 3
2696     * trace( "2013-05-05".date().diff("2013-05-08".date()) );
2697     * // 3
2698     * ```
2699     */
2700    function dayDiff(edDate, tp) {
2701        var DyMilli = ((1000 * 60) * 60) * 24;
2702        //trace(this.print() +"/"+ edDate.print() + "//" + ((edDate.date() - this) / DyMilli) + "//" + ((edDate.date() - this) / DyMilli).floor());
2703        var y1 = this.getFullYear();
2704        var m1 = this.getMonth();
2705        var d1 = this.getDate();
2706        var hh1 = this.getHours();
2707        var mm1 = this.getMinutes();
2708        var dd1 = new Date(y1, m1, d1, hh1, mm1, this.getSeconds());
2709
2710        var day2 = edDate.date();
2711        var y2 = day2.getFullYear();
2712        var m2 = day2.getMonth();
2713        var d2 = day2.getDate();
2714        var hh2 = day2.getHours();
2715        var mm2 = day2.getMinutes();
2716        var dd2 = new Date(y2, m2, d2, hh2, mm2, this.getSeconds());
2717
2718        if (tp != undefined) {
2719            if (tp == "D") {
2720                DyMilli = ((1000 * 60) * 60) * 24;
2721                dd2 = new Date(y2, m2, d2, hh1, mm1, this.getSeconds());
2722            }
2723            else if (tp == "H") {
2724                DyMilli = ((1000 * 60) * 60);
2725            }
2726            else if (tp == "mm") {
2727                DyMilli = (1000 * 60);
2728            }
2729            else {
2730                DyMilli = ((1000 * 60) * 60) * 24;
2731                dd2 = new Date(y2, m2, d2, hh1, mm1, this.getSeconds());
2732            }
2733        }
2734
2735        return ((dd2.getTime() - dd1.getTime()) / DyMilli).floor();
2736
2737    }
2738
2739    /**
2740     * @method  Date.print
2741     * @param {String} [format=yyyy-mm-dd]
2742     * @returns {type} name
2743     * @description yyyy:년도, mm:월, dd:일, hh:시, mi:분, ss:초, dw:요일 을 조합하여 format으로 지정하면 그에 맞는 날짜형식 문자열이 반환됩니다.
2744     * @example
2745     * ```js
2746     * "2013-05-05".date().print(); -> "2013-05-05"
2747     * "2013-05-05".date().print('yyyy년 mm월 dd일'); -> "2013년 05월 05일"
2748     * "2013-05-05".date().print('yyyy년 mm월 dd일 (dw)'); -> "2013년 05월 05일 (일)"
2749     * ```
2750     */
2751    function toString(format) {
2752        if (format == undefined) {
2753            var sSeper = "-";
2754            return this.getUTCFullYear() + sSeper + (this.getMonth() + 1).setDigit(2) + sSeper + this.getDate().setDigit(2);
2755        }
2756        else {
2757            var fStr = format;
2758            var nY, nM, nD, nH, nMM, nS, nDW;
2759            nY = this.getUTCFullYear();
2760            nM = (this.getMonth() + 1).setDigit(2);
2761            nD = this.getDate().setDigit(2);
2762            nH = this.getHours().setDigit(2);
2763            nMM = this.getMinutes().setDigit(2);
2764            nS = this.getSeconds().setDigit(2);
2765            nDW = this.getDay();
2766
2767            var yre = /[^y]*(yyyy)[^y]*/gi;
2768            yre.exec(fStr);
2769            var regY = RegExp.$1;
2770            var mre = /[^m]*(mm)[^m]*/gi;
2771            mre.exec(fStr);
2772            var regM = RegExp.$1;
2773            var dre = /[^d]*(dd)[^d]*/gi;
2774            dre.exec(fStr);
2775            var regD = RegExp.$1;
2776            var hre = /[^h]*(hh)[^h]*/gi;
2777            hre.exec(fStr);
2778            var regH = RegExp.$1;
2779            var mire = /[^m]*(mi)[^i]*/gi;
2780            mire.exec(fStr);
2781            var regMI = RegExp.$1;
2782            var sre = /[^s]*(ss)[^s]*/gi;
2783            sre.exec(fStr);
2784            var regS = RegExp.$1;
2785            var dwre = /[^d]*(dw)[^w]*/gi;
2786            dwre.exec(fStr);
2787            var regDW = RegExp.$1;
2788
2789            if (regY === "yyyy") {
2790                fStr = fStr.replace(regY, nY.right(regY.length));
2791            }
2792            if (regM === "mm") {
2793                if (regM.length == 1) nM = (this.getMonth() + 1);
2794                fStr = fStr.replace(regM, nM);
2795            }
2796            if (regD === "dd") {
2797                if (regD.length == 1) nD = this.getDate();
2798                fStr = fStr.replace(regD, nD);
2799            }
2800            if (regH === "hh") {
2801                fStr = fStr.replace(regH, nH);
2802            }
2803            if (regMI === "mi") {
2804                fStr = fStr.replace(regMI, nMM);
2805            }
2806            if (regS === "ss") {
2807                fStr = fStr.replace(regS, nS);
2808            }
2809            if (regDW == "dw") {
2810                fStr = fStr.replace(regDW, AXConfig.weekDays[nDW].label);
2811            }
2812            return fStr;
2813        }
2814    }
2815
2816    /**
2817     * @method  Date.getTimeAgo
2818     * @returns {String}
2819     * @description 현재와 날짜 데이터 간의 간격을 문자열로 반환합니다.
2820     * @example
2821     * ```js
2822     * var pDate = new Date();
2823     * pDate.setTime(pDate.getTime()-1000*60);
2824     * trace( pDate.getTimeAgo() );
2825     * // 1분 전
2826     *
2827     * pDate.setTime(pDate.getTime()-1000*60*5);
2828     * trace( pDate.getTimeAgo() );
2829     * //  6분 전
2830     *
2831     * pDate.setTime(pDate.getTime()-1000*60*60);
2832     * trace( pDate.getTimeAgo() );
2833     * //  1시간 6분 전
2834     *
2835     * pDate.setTime(pDate.getTime()-1000*60*60*24);
2836     * trace( pDate.getTimeAgo() );
2837     * //  2013년 11월 19일 화
2838     * ```
2839     */
2840    function getTimeAgo() {
2841
2842        var rtnStr = "";
2843        var nMinute = Math.abs((new Date()).diff(this, "mm"));
2844
2845        var wknames = [];
2846        wknames.push("일", "월", "화", "수", "목", "금", "토");
2847
2848        if (isNaN(nMinute)) {
2849            rtnStr = "알수없음";
2850        }
2851        else {
2852            if (parseInt(nMinute / 60 / 24) >= 1) {
2853                rtnStr = this.print("yyyy년 mm월 dd일") + " " + wknames[this.getDay()];
2854            }
2855            else {
2856                rtnStr = nMinute;
2857
2858                if ((nMinute / 60) > 1) {
2859                    rtnStr = parseInt(nMinute / 60) + "시간 " + (nMinute % 60) + "분 전";
2860                }
2861                else {
2862                    rtnStr = nMinute + "분 전";
2863                }
2864            }
2865        }
2866        return rtnStr;
2867    }
2868
2869    function date() { return this; }
2870
2871    function axtoJSON() { return '"' + this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).setDigit(2) + '-' + this.getUTCDate().setDigit(2) + 'T' + this.getUTCHours().setDigit(2) + ':' + this.getUTCMinutes().setDigit(2) + ':' + this.getUTCSeconds().setDigit(2) + 'Z"'; }
2872
2873    /**
2874     * @method  Date.axGetDay
2875     * @param {Number} [dayOfStart=0]
2876     * @returns {Number}
2877     * @description 요일의 시작인덱스를 변경한 요일인덱스를 반환합니다.
2878     */
2879    function axGetDay(dayOfStart) {
2880        if (dayOfStart == undefined) dayOfStart = 0;
2881        var myDay = this.getDay() - dayOfStart;
2882        if (myDay < 0) myDay = 7 + myDay;
2883        return myDay;
2884    }
2885
2886    return {
2887        add: dateAdd,
2888        diff: dayDiff,
2889        print: toString,
2890        date: date,
2891        axtoJSON: axtoJSON,
2892        getTimeAgo: getTimeAgo,
2893        axGetDay: axGetDay
2894    }
2895})());
2896
2897/**
2898 * Error.prototype
2899 * @namespace {Error} Error
2900 */
2901Object.extend(Error.prototype, (function () {
2902    /**
2903     * 에러넘버와 에러 객체를 리턴합니다.
2904     * @method Error.print
2905     * @returns {String}
2906     */
2907    function print() {
2908        return (this.number & 0xFFFF) + " : " + this;
2909    }
2910
2911    return {
2912        print: print
2913    }
2914})());
2915
2916/**
2917 * Array.prototype
2918 * @namespace {Array} Array
2919 */
2920Object.extend(Array.prototype, (function () {
2921    /**
2922     * @method Array.clear
2923     * @returns {Array}
2924     * @description Array를 빈 Array 로 변경합니다.
2925     * @example
2926     * ```js
2927     * var a = [1,2,3];
2928     * trace(a);
2929     * // [1, 2, 3]
2930     * trace(a.clear());
2931     * // []
2932     * trace(a);
2933     * // []
2934     * ```
2935     */
2936    function clear() {
2937        this.length = 0;
2938        return this;
2939    }
2940
2941    /**
2942     * @method Array.first
2943     * @returns {Object}
2944     * @description Array의 첫번째 아이템을 반환합니다.
2945     * @example
2946     * ```js
2947     * var a = [1,2,3];
2948     * trace(a.first());
2949     * // 1
2950     *
2951     * var b = [{a:"액시스제이"}, 2, 3];
2952     * trace(b.first());
2953     * // {"a":"액시스제이"}
2954     *
2955     * var c = [[1,2,3], 2, 3];
2956     * trace(c.first());
2957     * // [1, 2, 3]
2958     * ```
2959     */
2960    function first() {
2961        return this[0];
2962    }
2963
2964    /**
2965     * @method Array.last
2966     * @returns {Object}
2967     * @description Array의 마지막 아이템을 반환합니다.
2968     * @example
2969     * ```js
2970     * var a = [1,2,3];
2971     * trace(a.last());
2972     * // 1
2973     *
2974     * var b = [1, 2, {a:"액시스제이"}];
2975     * trace(b.last());
2976     * // {"a":"액시스제이"}
2977     *
2978     * var c = [1, 2, [1,2,3]];
2979     * trace(c.last());
2980     * // [1, 2, 3]
2981     * ```
2982     */
2983    function last() {
2984        return this[this.length - 1];
2985    }
2986
2987    /**
2988     * 인자값에 해당하는 인덱스의 아이템을 반환합니다.
2989     * @method Array.getToSeq
2990     * @param {Number} seq
2991     * @returns {Object}
2992     * @example
2993     * ```js
2994     * var a = [1,2,3];
2995     * trace(a.getToSeq(1));
2996     * // 2
2997     *
2998     * var a = [1,{a:2},3];
2999     * trace(a.getToSeq(1));
3000     * // {"a":2}
3001     * ```
3002     */
3003    function getToSeq(seq) {
3004        if (seq > (this.length - 1)) {
3005            return null;
3006        }
3007        else {
3008            return this[seq];
3009        }
3010    }
3011
3012    function axtoJSON(qoute) {
3013        var results = [];
3014        for (var i = 0; i < this.length; i++) results.push(Object.toJSON(this[i], qoute));
3015        return '[' + results.join(', ') + ']';
3016    }
3017
3018    function toJSONforMobile() {
3019        var results = [];
3020        for (var i = 0; i < this.length; i++) results.push(Object.toJSONforMobile(this[i]));
3021        return '[' + results.join(', ') + ']';
3022    }
3023
3024    /**
3025     * 사용자가 정의한 조건에 맞는 아이템을 제거한 Array 를 반환합니다.
3026     * @method Array.remove
3027     * @param {Function} callBack - remove 처리할 대상에 return true; 하면 true 인 대상이 제거 됩니다.
3028     * @returns {Array}
3029     * @example
3030     * ```js
3031     * var a = [1,2,3,4];
3032     * trace(a);
3033     * // [1, 2, 3, 4]
3034     * a = a.remove(function(idx, item){
3035	 *     return (item == 3);
3036	 * });
3037     * trace(a);
3038     * // [1, 2, 4]
3039     *  * var b = [1,2,3,4];
3040     * trace(b);
3041     * // [1, 2, 3, 4]
3042     * b = b.remove(function(){
3043	 *     return (this.item == 3 || this.index == 0);
3044	 * });
3045     * trace(b);
3046     * // [2, 4]
3047     * ```
3048     */
3049    function remove(callBack) {
3050        var _self = this;
3051        var collect = [];
3052        AXUtil.each(this, function (index, O) {
3053            if (!callBack.call({index: index, item: O}, index, O)) collect.push(O);
3054        });
3055        return collect;
3056    }
3057
3058    /**
3059     * 사용자가 정의한 조건에 맞는 아이템 갯수를 반환합니다.
3060     * @method Array.search
3061     * @param {Function} callBack
3062     * @returns {Number}
3063     * @example
3064     * ```js
3065     * var a = [1,2,3,4];
3066     * trace(a);
3067     * // [1, 2, 3, 4]
3068     * trace(a.search(function(idx, item){
3069	 *     return (item < 3);
3070	 * }));
3071     * // 2
3072     * ```
3073     */
3074    function search(callBack) {
3075        var _self = this;
3076        var collect = [];
3077        AXUtil.each(this, function (index, O) {
3078            if (callBack.call({index: index, item: O}, index, O)) collect.push(O);
3079        });
3080        return collect.length;
3081    }
3082
3083    /**
3084     * 사용자가 정의한 조건에 맞는 아이템을 모두 반환합니다.
3085     * @method Array.searchObject
3086     * @param {Function} callBack
3087     * @returns {Array}
3088     * @example
3089     * ```js
3090     * var a = [1,2,3,4];
3091     * trace(a);
3092     * // [1, 2, 3, 4]
3093     * trace(a.searchObject(function(idx, item){
3094	 *     return (item < 3);
3095	 * }));
3096     * // [1, 2]
3097     *
3098     * var b = [1,2,3,4];
3099     * trace(b);
3100     * // [1, 2, 3, 4]
3101     * trace(b.searchObject(function(idx, item){
3102	 *     return (this.item < 3);
3103	 * }));
3104     * // [1, 2]
3105     * ```
3106     */
3107    function getObject(callBack) {
3108        var _self = this;
3109        var collect = [];
3110        AXUtil.each(this, function (index, O) {
3111            if (callBack.call({index: index, item: O}, index, O)) collect.push(O);
3112        });
3113        return collect;
3114    }
3115
3116    /**
3117     * 사용자가 정의한 조건에 맞는 아이템을 한 개만 반환합니다.
3118     * @method Array.hasObject
3119     * @param {Function} callBack
3120     * @returns {Object}
3121     * @example
3122     * ```js
3123     * var a = [1,2,3,4];
3124     * trace(a);
3125     * // [1, 2, 3, 4]
3126     * trace(a.has(function(idx, item){
3127	 *     return (item == 3);
3128	 * }));
3129     * // 3
3130     *
3131     * var b = [1,2,3,4];
3132     * trace(b);
3133     * // [1, 2, 3, 4]
3134     * trace(b.has(function(idx, item){
3135	 *     return (this.item == 3);
3136	 * }));
3137     * // 3
3138     * ```
3139     */
3140    function hasObject(callBack) {
3141        var _self = this;
3142        var collect = null;
3143        AXUtil.each(this, function (index, O) {
3144            if (callBack.call({index: index, item: O}, index, O)) {
3145                collect = O;
3146                return false;
3147            }
3148        });
3149        return collect;
3150    }
3151
3152    /* 13-06-13 메소드 확장 */
3153
3154    /**
3155     * Object Array의 키를 정렬한후 가장 작은 값을 반환합니다.
3156     * @method Array.getMinObject
3157     * @param {String} key
3158     * @returns {Object}
3159     * @example
3160     * ```js
3161     * var myArray = [{a:99},{a:2},{a:1}];
3162     * myArray.getMinObject("a");
3163     * // Object {a: 1}
3164     * ```
3165     */
3166    function getMinObject(key) {
3167        var tempArray = this.concat();
3168        tempArray = tempArray.sort(function (pItem, nItem) {
3169            var v1 = pItem[key];
3170            var v2 = nItem[key];
3171            if (v1 < v2) return -1;
3172            else if (v1 > v2) return 1;
3173            else if (v1 == v2) return 0;
3174        });
3175        return (tempArray.first() || {});
3176    }
3177
3178    /**
3179     * Object Array의 키를 정렬한후 가장 큰 값을 반환합니다.
3180     * @method Array.getMaxObject
3181     * @param {String} key
3182     * @returns {Object}
3183     * @example
3184     * ```js
3185     * var myArray = [{a:2},{a:99},{a:1}];
3186     * myArray.getMaxObject("a");
3187     * // Object {a: 99}
3188     * ```
3189     */
3190    function getMaxObject(key) {
3191        var tempArray = this.concat();
3192        tempArray = tempArray.sort(function (pItem, nItem) {
3193            var v1 = pItem[key];
3194            var v2 = nItem[key];
3195            if (v1 < v2) return 1;
3196            else if (v1 > v2) return -1;
3197            else if (v1 == v2) return 0;
3198        });
3199        return (tempArray.first() || {});
3200    }
3201
3202    function m_notall(context) {
3203        context = context || function (x) { return x; };
3204        var result = true;
3205        var i = 0;
3206        while (i < this.length) {
3207            result = !Boolean(context(this[i]));
3208            if (!result) break;
3209            i++;
3210        }
3211        return result;
3212    }
3213
3214    function m_any(context) {
3215        context = context || function (x) { return x; };
3216        var result = false;
3217        var i = 0;
3218        while (i < this.length) {
3219            result = Boolean(context(this[i], i));
3220            if (result) break;
3221            i++;
3222        }
3223        return result;
3224    }
3225
3226    function m_find(context) {
3227        context = context || function (x) { return false; };
3228        var myselect;
3229        var i = 0;
3230        while (i < this.length) {
3231            if (context(this[i], i)) {
3232                myselect = this[i];
3233                break;
3234            }
3235            i++;
3236        }
3237        return myselect;
3238    }
3239
3240    function m_find2(context) {
3241        if (!Object.isFunction(context)) {
3242            findObj = context;
3243            context = function (x) { return (x == findObj); }
3244        }
3245        var myselect, myindex;
3246        var i = 0;
3247        while (i < this.length) {
3248            if (context(this[i], i)) {
3249                myselect = this[i];
3250                myindex = i;
3251                break;
3252            }
3253            i++;
3254        }
3255        return {obj: myselect, index: myindex};
3256    }
3257
3258    function m_findAll(context) {
3259        context = context || function (x) { return false; };
3260        var myselect = [];
3261        ;
3262        var i = 0;
3263        while (i < this.length) {
3264            if (context(this[i], i)) myselect.push(this[i]);
3265            i++;
3266        }
3267        return myselect;
3268    }
3269
3270    /**
3271     * 리스트형 데이터를 부모 참조키와 자식 참조키를 이용하여 트리형 데이터로 변환처리 합니다.
3272     * @method Array.convertTree
3273     * @param {String} parentKey
3274     * @param {String} childKey
3275     * @param {String} [hashDigit=3] - 트리의 주소값에 해당하는 hash 의 자릿수 단위 설정 (기본값 3)
3276     * @returns {Object}
3277     * @example
3278     * ```js
3279     * var a = [
3280     *     {pno:0, no:1, name:"장기영"},
3281     *     {pno:1, no:2, name:"장기영"},
3282     *     {pno:1, no:3, name:"장기영"},
3283     *     {pno:3, no:4, name:"장기영"},
3284     *     {pno:3, no:5, name:"장기영"},
3285     *     {pno:5, no:6, name:"장기영"},
3286     *     {pno:5, no:7, name:"장기영"}
3287     * ];
3288     *
3289     * var myTree = a.convertTree("pno", "no");
3290     * trace(myTree);
3291     * //[{"pno":0, "no":1, "name":"장기영", "subTree":[{"pno":1, "no":2, "name":"장기영", "__subTreeLength":0, "subTree":[], "pHash":"000_000", "hash":"000_000_000"}, {"pno":1, "no":3, "name":"장기영", "__subTreeLength":2, "subTree":[{"pno":3, "no":4, "name":"장기영", "__subTreeLength":0, "subTree":[], "pHash":"000_000_001", "hash":"000_000_001_000"}, {"pno":3, "no":5, "name":"장기영", "__subTreeLength":2, "subTree":[{"pno":5, "no":6, "name":"장기영", "__subTreeLength":0, "subTree":[], "pHash":"000_000_001_001", "hash":"000_000_001_001_000"}, {"pno":5, "no":7, "name":"장기영", "__subTreeLength":0, "subTree":[], "pHash":"000_000_001_001", "hash":"000_000_001_001_001"}], "pHash":"000_000_001", "hash":"000_000_001_001"}], "pHash":"000_000", "hash":"000_000_001"}], "__subTreeLength":2, "pHash":"000", "hash":"000_000"}]
3292     * ```
3293     */
3294    function convertTree(parentKey, childKey, hashDigit) {
3295        var tree = [];
3296        var pointer = {};
3297        var seq = 0;
3298        var hashDigit = hashDigit || 3;
3299        for (var idx = 0; idx < this.length; idx++) {
3300            var L = this[idx];
3301            if (!L.isRoot) {
3302                pointer[L[childKey]] = idx;
3303
3304                if (typeof L[parentKey] === "undefined" || L[parentKey] == "" || L[parentKey].number() == 0) {
3305                    L["subTree"] = [];
3306                    L.__subTreeLength = 0;
3307                    L["pHash"] = "0".setDigit(hashDigit);
3308                    L["hash"] = "0".setDigit(hashDigit) + "_" + seq.setDigit(hashDigit);
3309                    tree.push(AXUtil.copyObject(L));
3310                    seq++;
3311                }
3312                else {
3313                    L.__subTreeLength = 0;
3314                }
3315            }
3316        }
3317
3318        for (var idx = 0; idx < this.length; idx++) {
3319            var L = this[idx];
3320            if (L["pHash"] == undefined && !L.isRoot) {
3321                var pItem = this[pointer[L[parentKey]]];
3322                var pHash = pItem["hash"];
3323                var pHashs = pHash.split(/_/g);
3324                var pTree = tree;
3325                var pTreeItem;
3326                axf.each(pHashs, function (idx, T) {
3327                    if (idx > 0) {
3328                        pTreeItem = pTree[T.number()];
3329                        pTree = pTree[T.number()].subTree;
3330                    }
3331                });
3332                L["subTree"] = [];
3333                var __subTreeLength = pItem.__subTreeLength;
3334
3335                L["pHash"] = pHash;
3336                L["hash"] = pHash + "_" + __subTreeLength.setDigit(hashDigit);
3337                pTree.push(AXUtil.copyObject(L));
3338                pItem.__subTreeLength++;
3339                pTreeItem.__subTreeLength = pItem.__subTreeLength;
3340            }
3341        }
3342        return tree;
3343    }
3344
3345    /**
3346     * 조건에 맞는 아이템을 index 값과 함께 반환합니다.
3347     * @method Array.getIndex
3348     * @param {Function} context
3349     * @returns {Object}
3350     * @example
3351     * ```js
3352     * var b = [1,2,3,4];
3353     * trace(b);
3354     * // [1, 2, 3, 4]
3355     * trace(b.getIndex(function(idx, item){
3356	 *     return (this.item >= 3);
3357	 * }));
3358     * //  {"item":3, "index":2}
3359     * ```
3360     */
3361    function getIndex(context) {
3362        if (!Object.isFunction(context)) {
3363            findObj = context;
3364            context = function (x) { return (x == findObj); }
3365        }
3366        var findObject, findIndex;
3367        var i = 0;
3368        while (i < this.length) {
3369            var sobj = {
3370                index: i,
3371                item: this[i]
3372            };
3373            if (context.call(sobj, sobj)) {
3374                findObject = this[i];
3375                findIndex = i;
3376                break;
3377            }
3378            i++;
3379        }
3380        return {item: findObject, index: findIndex};
3381    }
3382
3383    return {
3384        clear: clear,
3385        first: first,
3386        last: last,
3387        getToSeq: getToSeq,
3388        axtoJSON: axtoJSON,
3389        toJSONforMobile: toJSONforMobile,
3390        remove: remove,
3391        search: search,
3392        has: hasObject,
3393        searchObject: getObject,
3394        getMinObject: getMinObject,
3395        getMaxObject: getMaxObject,
3396
3397        not: m_notall,
3398        or: m_any,
3399        get: m_find,
3400        gets: m_findAll,
3401        getObj: m_find2,
3402        getIndex: getIndex,
3403        convertTree: convertTree
3404    }
3405})());
3406
3407//JSON.stringify = Object.toJSON;
3408function AXgetId(id) { return document.getElementById(id); }
3409function AX_A(iterable) {
3410    if (!iterable) return [];
3411    if ('toArray' in Object(iterable)) return iterable.toArray();
3412    var length = iterable.length || 0, results = new Array(length);
3413    while (length--) results[length] = iterable[length];
3414    return results;
3415}
3416
3417var trace = axf.console;
3418var getUrlInfo = axf.getUrlInfo;
3419/* ---------------------------- */
3420/**
3421 * AXJ UI 클래스 기본형
3422 * @class AXJ
3423 */
3424var AXJ = Class.create({
3425/**
3426 * @member AXJ.config
3427 * @description UI클래스 설정 변수
3428 */
3429    initialize: function () {
3430        this.config = {
3431            debugMode: false,
3432            hashSpliter: "_",
3433            href: "href=\"javascript:;\""
3434        };
3435    },
3436    init: function () {
3437        trace(Object.toJSON(this.config));
3438    },
3439    echo: function (msg, mtype) {
3440        if (mtype == undefined || mtype == "console")
3441            trace(msg);
3442        else if (mtype == "alert")
3443            AXUtil.alert(msg);
3444        else if (mtype == "toast")
3445            toast.push(msg);
3446        else if (mtype == "dialog")
3447            dialog.push(msg);
3448    },
3449/**
3450 * @method AXJ.setConfig
3451 * @param {Object} configs - 속성오브젝트
3452 * @returns {AXJ}
3453 * @description UI 클래스의 속성을 정의 또는 재정의 하고 클래스내부에 init 메소드를 호출합니다.
3454 * @example
3455 ```js
3456myClass.setConfig({
3457	a:1, b:2, c:function(){}
3458});
3459 ```
3460 */
3461    setConfig: function (configs) {
3462		// overwrite this.config
3463		if (configs) {for ( k in configs ) {if (configs.hasOwnProperty(k)) this.config[k] = configs[k];}}
3464		// configs에 targetID가 없고 target만 지정한 경우 targetID 자동생성
3465        if(this.config.target) if(this.config.target.id === undefined || this.config.target.id == "") axdom(this.config.target).attr("id", this.config.target.id = this.config.targetID = "AXJUnique_"+axf.getUniqueId());
3466        this.init();
3467	    return this;
3468    },
3469/**
3470 * @method AXJ.changeConfig
3471 * @param {Object} configs - 속성오브젝트
3472 * @returns {AXJ}
3473 * @description UI 클래스의 속성을 변경 합니다.
3474 * @example
3475 ```js
3476myClass.changeConfig({
3477	a:1
3478});
3479 ```
3480 */
3481    changeConfig: function (configs) {
3482	    if (configs) {for ( k in configs ) {if (configs.hasOwnProperty(k)) this.config[k] = configs[k];}}
3483	    return this;
3484    },
3485/**
3486 * @method AXJ.getEventTarget
3487 * @param {Object} args - 설명
3488 * @returns {Null}
3489 * @description 설명
3490 * @example
3491 ```js
3492var myTarget = this.getEventTarget({
3493    evt : event.target,
3494	until:function(evt, evtIDs){
3495		// 선택 조건
3496		// event bubble 탐색 종료 시점 정의 함수 argument 로 받은 eventTarget 과 evtIDs 객체로 부터 다양한 조건으로 설정가능
3497		// return true; 하면 버블 탐색 종료 됨.
3498		// return ( axdom(evt.parentNode).hasClass("CTclassName") );
3499		return (evt.parentNode.tagName == "body");
3500	},
3501	find:function(evt, evtIDs){
3502		// return true; 하면 버블탐색 종료 후 현재 eventTarget 리턴
3503		//return ( axdom(evt).hasClass("colHeadTd") );
3504		return ( evt.id == objID || (evtIDs[0] == cfg.targetID && evtIDs[1] == objID) );
3505	}
3506});
3507
3508if(myTarget){
3509	//something
3510}
3511 ```
3512*/
3513    getEventTarget: function (args) {
3514        var eventTarget = args.evt;
3515        var eid = (eventTarget && eventTarget.id && eventTarget.id != "") ? eventTarget.id.split(/_AX_/g) : [];
3516        if (eventTarget) {
3517            while (!args.find(eventTarget, eid)) {
3518                if (!eventTarget.parentNode) { eventTarget = null; break; }
3519                if (args.until) { if (args.until(eventTarget, eid)) { eventTarget = null; break; } }
3520                if (eventTarget.parentNode) {
3521                    eventTarget = eventTarget.parentNode;
3522                    try {
3523                        eid = (eventTarget && eventTarget.id && eventTarget.id != "") ? eventTarget.id.split(/_AX_/g) : [];
3524                    } catch (e) {
3525                        eid = [];
3526                    }
3527                } else {
3528                    break;
3529                }
3530            }
3531        }
3532        return eventTarget;
3533    },
3534/**
3535 * @method AXJ.getMousePositon
3536 * @param {eventObject} event
3537 * @returns {Object} css - pageX, pageY
3538 * @description 스크롤된 페이지에서 이벤트의 마우스 x,y 페이지포지션을 구해줍니다.
3539 */
3540    getMousePositon: function (event) {
3541        var eventDoc, doc, body;
3542        eventDoc = document;
3543        doc = eventDoc.documentElement;
3544        body = eventDoc.body;
3545        var css = {};
3546
3547        //trace({ cy: event.clientY, st: (doc && doc.scrollTop || body && body.scrollTop || 0), ct: (doc && doc.clientTop || body && body.clientTop || 0) });
3548        css.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
3549        css.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
3550        return css;
3551    },
3552/**
3553 * @method AXJ.stopEvent
3554 * @param {eventObject} event - 이벤트
3555 * @description 이벤트 버블링을 중지 합니다.
3556 * @example
3557```js
3558var _this = this;
3559axdom("#" + elementID).on("mousedown", function(event){
3560	_this.stopEvent();
3561});
3562 ```
3563 */
3564    stopEvent: function (event) {
3565		try {
3566			if (event.preventDefault) event.preventDefault();
3567	        if (event.stopPropagation) event.stopPropagation();
3568			event.cancelBubble = true;
3569		}catch(e){
3570
3571		}
3572        return false;
3573    },
3574/**
3575 * @method AXJ.clearRange
3576 * @returns {AXJ}
3577 * @description 현재 페이지의 모든 사용자 선택을 취소 합니다.
3578 * @example
3579```js
3580this.clearRange();
3581```
3582 */
3583    clearRange: function () {
3584        if (window.getSelection) {
3585            if (window.getSelection().empty) {  // Chrome
3586                window.getSelection().empty();
3587            } else if (window.getSelection().removeAllRanges) {  // Firefox
3588                window.getSelection().removeAllRanges();
3589            }
3590        } else if (document.selection) {  // IE?
3591            document.selection.empty();
3592        }
3593		return this;
3594    },
3595/**
3596 * @method AXJ.windowResize
3597 * @description windowResizeApply메소드 호출을 연속으로 수행되지 않도록 하는 보호장치
3598 * @example
3599```js
3600 var _this = this;
3601 $(window).resize(function(){
3602   _this.windowResize();
3603 });
3604 // 결과적으로 windowResizeApply가 호출됩니다.
3605```
3606 */
3607    windowResize: function () {
3608        var windowResizeApply = this.windowResizeApply.bind(this);
3609        if (this.windowResizeObserver) clearTimeout(this.windowResizeObserver);
3610        this.windowResizeObserver = setTimeout(function () {
3611            windowResizeApply();
3612        }, 1);
3613    },
3614    windowResizeApply: function () {
3615
3616    }
3617});
3618
3619/**
3620 * @namespace {jQueryObject} jQueryExtends
3621 */
3622
3623// -- AXReq ----------------------------------------------
3624/**
3625 * @class AXReqQue
3626 * @version v1.4
3627 * @author [email protected]
3628 * @logs
3629 * 2012-09-28 오후 2:58:32 - 시작
3630 * 2014-04-10 - tom : onbeforesend 옵션 추가 return false 하면 호출 제어됨.
3631 * 2014-10-06 - tom : dataSendMethod bug fix.
3632 * 2014-12-31 - tom : AXConfig.AXReq.pars 확장
3633 * 2015-03-19 - tom : AXConfig.AXReq.dataSendMethod = "json|query-json|parameter" 옵션을 수용하도록 변경 *
3634 */
3635var AXReqQue = Class.create({
3636/**
3637 * AJAX호출 큐
3638 * @member {Array} AXReqQue.que
3639 */
3640/**
3641 * AJAX호출 진행상태
3642 * @member {Boolean} AXReqQue.busy
3643 */
3644    initialize: function () {
3645        this.que = [];
3646        this.busy = false;
3647    },
3648/**
3649 * @method AXReqQue.add
3650 * @param {Object} obj - ajax config
3651 * @returns {AXReqQue}
3652 * @description que.push
3653 */
3654    add: function (obj) {
3655        this.que.push(obj);
3656        try {
3657            this.start();
3658        } catch (e) {
3659
3660        }
3661		return this;
3662    },
3663/**
3664 * @method AXReqQue.start
3665 * @description que에 담긴 AJAX호출을 처리합니다.
3666 */
3667    start: function () {
3668        if (this.que.length == 0) return;
3669        if (this.busy) return;
3670
3671        this.busy = true;
3672        var myQue = this.que.first();
3673        var _self = this;
3674        var config = {
3675            type: "post",
3676            onsucc: "",
3677            async: AXConfig.AXReq.async,
3678            responseType: AXConfig.AXReq.responseType,
3679            dataType: AXConfig.AXReq.dataType,
3680            contentType: AXConfig.AXReq.contentType,
3681            debug: false
3682        };
3683        axf.each(myQue.configs, function (k, v) { // update to {this.config}
3684            if (k == "pars") {
3685
3686            }
3687            else {
3688                config[k] = v;
3689            }
3690        });
3691
3692        var onerr = this.onerror.bind(this);
3693        var ontimeout = this.ontimeout.bind(this);
3694        var onsucc = this.onsucc.bind(this);
3695		var dataSendMethod = (myQue.configs.dataSendMethod || AXConfig.AXReq.dataSendMethod || "");
3696        if (dataSendMethod != "json") {
3697
3698        } else {
3699            if (typeof myQue.configs.pars == "object") {
3700                myQue.configs.pars.dummy = AXUtil.timekey();
3701            } else if (typeof myQue.configs.pars == "string") {
3702                if (myQue.configs.pars == "") myQue.configs.pars += "dummy=" + AXUtil.timekey();
3703                else myQue.configs.pars += "&dummy=" + AXUtil.timekey();
3704            }
3705        }
3706
3707        if (config.debug) trace({ url: myQue.url, pars: myQue.configs.pars });
3708
3709        var ajaxOption = {}, pars;
3710        axf.each(config, function (k, v) { // update to {this.config}
3711            ajaxOption[k] = v;
3712        });
3713        ajaxOption.url = myQue.url;
3714        pars = myQue.configs.pars;
3715        if(dataSendMethod != "DTO" && AXConfig.AXReq.pars){
3716            if (typeof pars == "object") {
3717                if (typeof AXConfig.AXReq.pars == "object") {
3718                    pars = jQuery.extend(pars, AXConfig.AXReq.pars);
3719                } else if (typeof AXConfig.AXReq.pars == "string") {
3720                    pars = jQuery.extend(pars, AXConfig.AXReq.pars.queryToObject());
3721                }
3722            }else if (typeof pars == "string") {
3723                if (typeof AXConfig.AXReq.pars == "object") {
3724                    pars += "&" + jQuery.param(AXConfig.AXReq.pars);
3725                } else if (typeof AXConfig.AXReq.pars == "string") {
3726                    pars += "&" + AXConfig.AXReq.pars;
3727                }
3728            }
3729        }
3730
3731		if (dataSendMethod == "json") {
3732			ajaxOption["data"] = Object.toJSON( ((typeof pars == "string") ? pars.queryToObject() : pars ) );
3733		}else if (dataSendMethod == "query-json") {
3734			ajaxOption["data"] = "{queryString:\"" + pars + "\"}";
3735		}else {
3736			ajaxOption["data"] = pars;
3737		}
3738
3739		ajaxOption.success = onsucc;
3740        ajaxOption.error = onerr;
3741        ajaxOption.timeout = ontimeout;
3742
3743        if (myQue.configs.onbeforesend) {
3744            if(!myQue.configs.onbeforesend.call(ajaxOption)){
3745                return false;
3746            }
3747        }
3748
3749        this.que[0]._jQueryAjax = axdom.ajax(ajaxOption);
3750    },
3751    onsucc: function (req) {
3752        if (req != undefined) {
3753            var myQue = this.que.first(), res;
3754
3755            try {
3756                if (myQue.configs.debug) trace("onsucc" + req);
3757
3758                if (myQue.configs.responseType == "text/html") {
3759                    res = req;
3760                } else {
3761                    if ((typeof req) == "string") {
3762                        res = req.object();
3763                    } else {
3764                        res = AXConfig.AXReq.resultFormatter.call(req);
3765                    }
3766                }
3767
3768                if (res.result == "syntaxerr") {
3769                    if (myQue.configs.onerr) myQue.configs.onerr(res);
3770                } else {
3771                    if (myQue.configs.onsucc) myQue.configs.onsucc(res);
3772                }
3773            } catch (e) {
3774                if (myQue.configs.responseType == "text/html") {
3775
3776                } else {
3777                    res.e = e;
3778                }
3779                if (myQue.configs.onerr) myQue.configs.onerr(res);
3780            }
3781
3782            this.que.shift();
3783            this.busy = false;
3784            this.start();
3785        }
3786    },
3787    onerror: function (req) {
3788        var myQue = this.que.first();
3789        if (myQue.configs.onerr) myQue.configs.onerr(req);
3790        else trace("error : " + Object.toJSON(req));
3791
3792        this.que.shift();
3793        this.busy = false;
3794        try {
3795            mask.close();
3796        } catch (e) { }
3797    },
3798    ontimeout: function (req) {
3799        trace("onTimeout:" + req.responseText);
3800        this.que.shift();
3801        this.busy = false;
3802        try {
3803            mask.close();
3804        } catch (e) { }
3805    },
3806/**
3807 * @method AXReqQue.abort
3808 * @returns {AXReqQue} AXReqQue
3809 * @description 설명
3810 * @example
3811```js
3812 // AXCore.js파일 에서 미리선언된 AXReqQue의 인스턴스 myAXreqQue를 이용하여 abort 명령을 내릴수 있습니다.
3813 myAXreqQue.abort();
3814 // 또는
3815 AXReqAbort();
3816 // 현재 진행중인 AJAX호출을 취소시켜줍니다.
3817```
3818 */
3819    abort: function(){
3820        try{
3821            this.que[0]._jQueryAjax.abort();
3822        }catch(e){
3823
3824        }
3825		return this;
3826    }
3827});
3828var myAXreqQue = new AXReqQue();
3829var AXReqAbort = function(){
3830    myAXreqQue.abort();
3831};
3832
3833/**
3834 * @class AXReq
3835 * @param {String} url - 비동기 호출 URL
3836 * @param {Object} config - 비동기 호출 설정
3837 * @description AJAX 호출구문을 AXReqQue 에 add 하여 비동기 호출합니다.
3838 * @example
3839```
3840var url = "";
3841var pars = "";
3842new AXReq(url, {
3843	debug: [true|false] default false,
3844	type: ["GET"|"POST"|"PUT"|"DELETE"|String] default "POST",
3845	contentType: [AJAX content type] optional,
3846	responseType: [AJAX response type] optional,
3847	dataType: [Ajax data type] optional,
3848	headers: [AJAX headers] optional,
3849	pars: [parameter|Object],
3850	onsucc: [Function],
3851	onerr: [Function] optional
3852});
3853```
3854 */
3855var AXReq = Class.create({
3856    initialize: function (url, configs) {
3857        myAXreqQue.add({ url: url, configs: configs });
3858    }
3859});
3860/* ---------------------------------------------- AXReq -- */
3861
3862/* -- AXMask ---------------------------------------------- */
3863/**
3864 * @class AXMask
3865 * @version v1.4
3866 * @author [email protected]
3867 * @logs
3868 * 2012-09-28 오후 2:58:32 - 시작
3869 * append 메소드 추가
3870 * 2014-09-17 hyunjun19 : 지정한 대상의 영역만 masking 하도록 style 추가
3871 * 2015-04-19 tom : body.data에 마스크상태값 저장
3872 * 2015-05-16 tom : mask.close(delay) 중 open 되면 예외처리, open상태에서 다시 open 도 예외처리
3873 * @description 웹페이지 전체에 사용자 입력을 막기위한 마스크를 추가하는데 사용
3874 * ```js
3875 mask.open();
3876 ```
3877 *
3878 */
3879var AXMask = Class.create(AXJ, {
3880    initialize: function (AXJ_super) {
3881        AXJ_super();
3882        this.selects = [];
3883        this.config.maskClassName = "AXMask";
3884        this.config.maskContentClassName = "AXMaskContent";
3885        this.config.content = "disable content";
3886        this.config.maskZindex = "5000";
3887        this.blinkTrack = [];
3888    },
3889    init: function () {
3890        this.mask = axdom("<div class=\"" + this.config.maskClassName + "\" style=\"z_index:" + this.config.maskZindex + "\"></div>");
3891    },
3892    open: function (configs) {
3893        if(this.maskDelay) clearTimeout(this.maskDelay);
3894        if(axdom(document.body).data("masked") != "true"){
3895            axdom(document.body).append(this.mask);
3896            axdom(document.body).data("masked", "true");
3897            var bodyHeight = 0;
3898            (AXUtil.docTD == "Q") ? bodyHeight = document.body.clientHeight : bodyHeight = document.documentElement.clientHeight;
3899
3900            if (configs) {
3901                if (!configs.onclick) configs.onclick = configs.onClick;
3902                if (configs.onclick) {
3903                    this.mask.bind("click.AXMask", configs.onclick);
3904                }
3905            }
3906        }
3907    },
3908    append: function (targetID, configs) {
3909        var target = axdom("#"+targetID);
3910        if (target.css("position") == "static") { target.css("position", "relative") }
3911        target.append(this.mask.css({ 'position': 'absolute', 'top': 0, 'left': 0 }));
3912
3913        if(configs){
3914            if(!configs.onclick) configs.onclick = configs.onClick;
3915            if(configs.onclick){
3916                this.mask.bind("click.AXMask", configs.onclick);
3917            }
3918        }
3919    },
3920    close: function (delay) {
3921        if (!delay) {
3922            this.mask.unbind("click.AXMask");
3923            this.mask.remove();
3924            axdom(document.body).data("masked", null);
3925        } else {
3926            var maskHide = this.hide.bind(this);
3927            if(this.maskDelay) clearTimeout(this.maskDelay);
3928            this.maskDelay = setTimeout(maskHide, delay);
3929        }
3930        this.blinkTrack.clear();
3931    },
3932    hide: function () {
3933        this.mask.unbind("click.AXMask");
3934        this.mask.remove();
3935        axdom(document.body).data("masked", null);
3936        this.blinkTrack.clear();
3937    },
3938    setCSS: function (CSS) {
3939        this.mask.css(CSS);
3940    },
3941    addClass: function (className) {
3942        this.mask.addClass(className);
3943    },
3944    removeClass: function (className) {
3945        this.mask.removeClass(className);
3946    },
3947    blink: function (obj) {
3948        this.blinkTrack = [{ css: { opacity: 0.1 }, time: 1000 }, { css: { opacity: 0.8 }, time: 1000 }];
3949        if (obj) this.blinkTrack = obj;
3950        this.blinking(0);
3951    },
3952    stopBlink: function (obj) {
3953        this.blinkTrack.clear();
3954    },
3955    blinking: function (blinkIndex) {
3956        if (this.blinkTrack.length > 0) {
3957            var blinkTrack = this.blinkTrack;
3958            var onblink = this.blinking.bind(this);
3959            this.mask.animate(blinkTrack[blinkIndex].css, blinkTrack[blinkIndex].time, 'circInOut', function () {
3960                onblink((blinkIndex + 1) % blinkTrack.length);
3961            });
3962        }
3963    },
3964    setContent: function(content){
3965        var po = [];
3966        if(Object.isString(content)){
3967            po.push(content);
3968        }else{
3969            var po = [];
3970            po.push("<div style='width: "+content.width+"px;height:"+content.height+"px;position: absolute;left:50%;top:50%;text-align: center;margin-left: -"+ (content.width/2) +"px;margin-top:-"+ (content.height/2) +"px;'>");
3971            po.push(content.html);
3972            po.push("</div>")
3973        }
3974        this.mask.html(po.join(''));
3975    }
3976});
3977var mask = new AXMask();
3978mask.setConfig();
3979
3980/**
3981 * @method AXMask.open
3982 * @param {Object} config - 설명
3983 * @returns {Null}
3984 * @description 설명
3985 * @example
3986```
3987 mask.open({onclick:function(){
3988    // mask click event
3989 });
3990 mask.open();
3991```
3992 */
3993
3994
3995/**
3996 * @method jQueryExtends.mask
3997 * @param {Object} config - 설명
3998 * @returns {jQueryObject}
3999 * @description mask 삽입위치를 엘리먼트 다음의 위치로 합니다.
4000 * @example
4001 ```
4002 $("#target").mask();
4003 $("#target").mask({
4004    onclick: function(){
4005        // mask click event
4006    }
4007 });
4008 ```
4009 */
4010axdom.fn.mask = function (configs) {
4011	axf.each(this, function () {
4012		mask.append(this.id, configs);
4013	});
4014	return this;
4015};
4016
4017/* ---------------------------------------------- AXMask -- */
4018
4019/* -- AXNotification ---------------------------------------------- */
4020/**
4021 * AXNotification
4022 * @class AXNotification
4023 * @extends AXJ
4024 * @version v1.7
4025 * @author [email protected]
4026 * @logs
4027 "2012-10-30 오후 12:01:10",
4028 "2013-01-09 오후 1:46:55 push type bug fix - tom"
4029 "2014-05-23 tom : dialog 에서 mask 제어 안하도록 변경"
4030 "2014-05-26 tom : dialog 에서 top 속성 설정 추가"
4031 "2014-08-16 tom : dialog body에서 \n -> <br/> auto replace "
4032 "2014-08-25 tom : dialog body에서 \n -> <br/> auto replace 예외처리 "
4033 "2015-01-12 tom : ie7,8 fadeOut error fix https://github.com/axisj-com/axisj/issues/386"
4034 "2015-01-19 tom : https://github.com/axisj-com/axisj/issues/392 dialog에 onConfirm 추가"
4035 "2015-04-14 tom : https://github.com/axisj-com/axisj/issues/532 dialog에 onclose 추가"
4036 */
4037var AXNotification = Class.create(AXJ, {
4038    initialize: function (AXJ_super) {
4039        AXJ_super();
4040        this.Observer = null;
4041        this.lasBreadSeq = 0;
4042        this.bread = [];
4043        this.config.easing = { open: { duration: 300, easing: "expoOut" }, close: { duration: 500, easing: "expoOut" } };
4044        this.config.eatUpTime = 2500;
4045        this.config.confirmStr = "확인";
4046        this.config.cancelStr = "취소";
4047    },
4048    init: function () {
4049        var config = this.config;
4050        if (config.type == "toast") {
4051            this.toastTray = axdom("<div class=\"AXNotificationTray\" id=\"" + config.targetID + "\"></div>");
4052        } else if (config.type == "dialog") {
4053            this.dialogTray = axdom("<div class=\"AXNotificationTrayDialog\" id=\"" + config.targetID + "\"></div>");
4054            //dialog type display center;
4055        }
4056    },
4057    push: function (obj) {
4058        var config = this.config;
4059        var breadID = config.targetID + "" + this.lasBreadSeq;
4060        this.lasBreadSeq++;
4061
4062        var po = [];
4063        if ((typeof obj).toLowerCase() != "object") {
4064            po.push("<div class=\"AXNotification\" id=\"bread_AX_" + breadID + "\" style=\"display:none;\">");
4065            if (config.type == "dialog") {
4066                po.push("<div class=\"AXNotificationHead\">" + (obj.title || "Dialog Message") + "</div>");
4067            }
4068            po.push("<div class=\"AXNotificationCT\">");
4069            po.push("	<table cellpadding=\"0\" cellspacing=\"0\" class=\"AXNotificationTable\">");
4070            po.push("		<tbody>");
4071            po.push("			<tr>");
4072            po.push("				<td class=\"AXNotificationIcon\"></td>");
4073            po.push("				<td class=\"AXNotificationBody\">");
4074	        if(Object.isString(obj)){
4075		        po.push(obj.crlf());
4076	        }else{
4077		        po.push(obj);
4078	        }
4079            po.push("				</td>");
4080            po.push("			</tr>");
4081            po.push("		</tbody>");
4082            po.push("	</table>");
4083
4084            if (config.type == "dialog") {
4085                po.push("	<div class=\"AXNotificationButtons\">");
4086                po.push("	<input type=\"button\" value=\"" + config.confirmStr + "\" class=\"AXButton Red\"  id=\"bread_AX_" + breadID + "_AX_confirm\" />");
4087                po.push("	</div>");
4088            }
4089
4090            po.push("</div>");
4091            po.push("</div>");
4092
4093        } else {
4094            po.push("<div class=\"AXNotification " + obj.type + "\" id=\"bread_AX_" + breadID + "\" style=\"display:none;\">");
4095            if (config.type == "dialog") {
4096                po.push("<div class=\"AXNotificationHead\">" + (obj.title || "Dialog Message") + "</div>");
4097            }
4098            po.push("<div class=\"AXNotificationCT\">");
4099            po.push("	<table cellpadding=\"0\" cellspacing=\"0\" class=\"AXNotificationTable\">");
4100            po.push("		<tbody>");
4101            po.push("			<tr>");
4102            po.push("				<td class=\"AXNotificationIcon\"></td>");
4103            po.push("				<td class=\"AXNotificationBody\">");
4104            if(Object.isString(obj.body)){
4105	            po.push(obj.body.crlf());
4106            }else{
4107	            po.push(obj.body);
4108            }
4109            po.push("				</td>");
4110            if (obj.type == "Caution" && config.type != "dialog") {
4111                if (!obj.buttons) {
4112                    po.push("				<td class=\"AXNotificationButton\" align=\"right\">");
4113                    po.push("				<input type=\"button\" value=\"" + config.confirmStr + "\" class=\"AXButton Red\"  id=\"bread_AX_" + breadID + "_AX_confirm\" />");
4114                    po.push("				</td>");
4115                }
4116            }
4117            po.push("			</tr>");
4118            po.push("		</tbody>");
4119            po.push("	</table>");
4120            if (obj.buttons) {
4121                po.push("	<div class=\"AXNotificationButtons\">");
4122                AXUtil.each(obj.buttons, function (index, B) {
4123                    po.push("	<input type=\"button\" value=\"" + this.buttonValue + "\" class=\"AXButton " + (this.buttonClass || "") + "\"  id=\"bread_AX_" + breadID + "_AX_buttons_AX_" + index + "\" />");
4124                });
4125                po.push("	</div>");
4126            } else if (config.type == "dialog") {
4127                po.push("	<div class=\"AXNotificationButtons\">");
4128                po.push("	<input type=\"button\" value=\"" + config.confirmStr + "\" class=\"AXButton Red\"  id=\"bread_AX_" + breadID + "_AX_confirm\" />");
4129                po.push("	</div>");
4130            }
4131            po.push("</div>");
4132            po.push("</div>");
4133
4134        }
4135
4136        if (config.type == "toast") {
4137            if (!AXgetId(config.targetID)) axdom(document.body).append(this.toastTray);
4138            this.bread.push({ breadID: breadID, type: obj.type, html: po.join('').enc() });
4139            this.insertBread(obj);
4140        }
4141        else
4142        if (config.type == "dialog") {
4143            if (!AXgetId(config.targetID)) axdom(document.body).append(this.dialogTray);
4144            this.dialogTray.prepend(po.join(''));
4145
4146            var bodyWidth = (AXUtil.docTD == "Q") ? document.body.clientWidth : document.documentElement.clientWidth;
4147            //var l = bodyWidth / 2 - this.dialogTray.width() / 2;
4148	        if(obj.top != undefined){
4149		        this.dialogTray.css({ top:obj.top });
4150	        }else{
4151		        this.dialogTray.css({ top:50 });
4152	        }
4153
4154            var breadBox = axdom("#bread_AX_" + breadID);
4155            breadBox.fadeIn();
4156
4157            var endCheck = this.endCheck.bind(this);
4158
4159            //Confirm button
4160            axdom("#bread_AX_" + breadID + "_AX_confirm").bind("click", function () {
4161                if (obj.onConfirm) obj.onConfirm(obj.data);
4162                breadBox.find("button, input").hide();
4163                breadBox.fadeOut({
4164                    duration: config.easing.close.duration, easing: config.easing.close.easing, complete: function () {
4165                        breadBox.remove();
4166                        endCheck();
4167                    }
4168                });
4169            });
4170
4171            //AXBUTTON
4172            axdom(".AXNotificationButtons").find(".AXButton").bind("click", function (event) {
4173                var eid = event.target.id.split(/_AX_/g);
4174                var myBreadID = eid[1];
4175                var buttonSeq = eid.last(), breadBox = axdom("#bread_AX_" + myBreadID);
4176                if (obj.buttons) {
4177                    if (obj.buttons[buttonSeq]) {
4178                        if (obj.buttons[buttonSeq].onClick) obj.buttons[buttonSeq].onClick(obj.buttons[buttonSeq].data);
4179                    }
4180                }
4181                breadBox.find("button, input").hide();
4182                breadBox.fadeOut({
4183                    duration: config.easing.close.duration, easing: config.easing.close.easing, complete: function () {
4184                        breadBox.remove();
4185                        endCheck();
4186                    }
4187                });
4188            });
4189
4190            axdom(".AXNotificationButtons").find(".AXButton").get(0).focus();
4191
4192            axdom(document.body).unbind("keyup."+breadID).bind("keyup."+breadID, function(event){
4193                if(event.keyCode == AXUtil.Event.KEY_ESC){
4194                    axdom("#bread_AX_" + breadID).fadeOut({
4195                        duration: config.easing.close.duration, easing: config.easing.close.easing, complete: function () {
4196                            axdom("#bread_AX_" + breadID).remove();
4197                            endCheck(breadID, obj);
4198                        }
4199                    });
4200                }
4201            });
4202        }
4203    },
4204    insertBread: function (obj) {
4205        var config = this.config;
4206        if (this.bread.length == 0) {
4207            return;
4208        }
4209        if (this.busy) return;
4210        this.busy = true;
4211
4212        var nextBread = this.nextBread.bind(this);
4213        var endCheck = this.endCheck.bind(this);
4214
4215        var myQue = this.bread.first();
4216        var breadID = myQue.breadID, breadBox;
4217        axdom("#" + config.targetID).prepend(myQue.html.decode());
4218        breadBox = axdom("#bread_AX_" + breadID);
4219
4220        axdom("#bread_AX_" + breadID + "_AX_confirm").bind("click", function () {
4221            if (obj.onConfirm) obj.onConfirm(obj.data);
4222            breadBox.find("button, input").hide();
4223            breadBox.fadeOut({
4224                duration: config.easing.close.duration, easing: config.easing.close.easing, complete: function () {
4225                    breadBox.remove();
4226                    endCheck();
4227                }
4228            });
4229        });
4230
4231        axdom("#bread_AX_" + breadID).slideDown({
4232            duration: config.easing.open.duration, easing: config.easing.open.easing, complete: function () {
4233                nextBread();
4234                //axdom("#msg").html(axdom("#msg").html()+"<br/>"+AXgetId("bread_AX_"+breadID)+"/"+breadID);
4235                if (myQue.type != "Caution") {
4236                    setTimeout(function () {
4237                        breadBox.fadeOut({
4238                            duration: config.easing.close.duration, easing: config.easing.close.easing, complete: function () {
4239                                breadBox.remove();
4240                                endCheck();
4241                            }
4242                        });
4243                    }, config.eatUpTime);
4244                }
4245            }
4246        });
4247    },
4248    nextBread: function () {
4249        this.bread.shift();
4250        this.busy = false;
4251        this.insertBread();
4252    },
4253    endCheck: function (breadID, obj) {
4254        if (axdom("#" + this.config.targetID).html() == "") {
4255            this.lasBreadSeq = 0;
4256            if (this.config.type == "dialog") {
4257                if(breadID) {
4258                    axdom(document.body).unbind("keyup." + breadID);
4259                    if(obj && obj.onclose) obj.onclose.call(obj, obj);
4260                }
4261            }
4262        }
4263    }
4264});
4265
4266/**
4267 * @method AXNotification.push
4268 * @param {Object|String} content - 대상물 문자열 혹은 오브젝트로 구성
4269 * @description notification은 dialog, toast 2가지 형태가 존재하고 각각 push 메소드를 이용하여 출력한다.
4270 * @example
4271```
4272 //toast
4273 toast.push('<b>Complete</b>\n Complete messange send !!');
4274 toast.push({body:'<b>Warning</b> Warning messange send !!', type:'Warning'});
4275 toast.push({body:'<b>Caution</b> Caution messange send !!', type:'Caution'});
4276
4277 //dialog
4278 dialog.push('<b>Alert</b>\n Application Call dialog push');
4279 dialog.push({body:'<b>Warning</b> Application Call dialog push', type:'Warning'});
4280 dialog.push({body:'<b>Caution</b> Application Call dialog push', type:'Caution', onConfirm:fnObj.btnOnConfirm, data:'onConfirmData'});
4281 dialog.push({
4282	body:'<b>Caution</b> Application Call dialog push', top:0, type:'Caution', buttons:[
4283	    {buttonValue:'button1', buttonClass:'Red W100', onClick:fnObj.btnClick, data:'data1'},
4284	    {buttonValue:'button2', buttonClass:'Blue', onClick:fnObj.btnClick, data:'data2'},
4285	    {buttonValue:'button3', buttonClass:'Green', onClick:fnObj.btnClick, data:'data3'}
4286	]
4287 });
4288```
4289 */
4290var toast = new AXNotification();
4291toast.setConfig({ targetID: "basicToast", type: "toast" });
4292
4293var dialog = new AXNotification();
4294dialog.setConfig({ targetID: "basicDialog", type: "dialog" });
4295/* ---------------------------------------------- AXNotification -- */
4296
4297/**
4298 * AXScroll
4299 * @class AXScroll
4300 * @extends AXJ
4301 * @version v1.53.1
4302 * @author [email protected], axisj.com
4303 * @logs
4304 "2012-10-10 오전 11:17:34",
4305 "2013-01-08 오후 2:33:39 스크롤대상을 스크롤바에서 컨테이너 기준으로 변경 - root",
4306 "2013-01-09 오후 1:29:26 mobile 환경에서 클릭버그수정 - tom",
4307 "2013-01-11 오후 4:18:21 스크롤바 드래그시 컨테이너 top 계산 수정-root",
4308 "2013-01-11 오후 5:18:54 컨테이너와 스크롤타겟의 높이에 따른 스크롤바표시 관련 수정-root",
4309 "2013-01-31 오후 3:10:02 스크롤바가 최소일때 휠 및 드래그 계산수정-root ",
4310 "2013-02-08 오후 5:48:26 컨테이너가 스크롤타켓보다 길때 휠 함수 중단 처리 - tom",
4311 "2013-02-16 오후 4:13:16 unbind 후 다시 bind할때 생기는 이벤트 중첩현상 처리 - tom",
4312 "2013-08-01 오후 4:54:17 mobile touch 버그픽스 - tom ",
4313 "2013-10-16 오후 6:45:48 mobile 스크롤 속도문제 패치 - tom",
4314 "2013-11-28 오전 11:23:11 tom - AX scrollTop 메소드 추가",
4315 "2013-12-12 오전 10:25:28 tom - moveTo 메소드 추가",
4316 "2014-01-06 오후 12:55:20 tom - 관성 작용중 touchStart stop 버그픽스",
4317 "2014-03-31 오후 6:26:34 root - yscroll 이 없어지면 scroll top 을 0으로"
4318 "2014-06-13 tom scrollBar 와 content 싱크방식 변경 / 버그픽스"
4319 "2014-07-14 tom issue#221, issue#222 fix"
4320 "2014-08-20 tom focusElement 버그픽스"
4321 "2014-08-28 tom setSBPosition 예외사항 exeception"
4322 * @example
4323 *```js
4324 * var myUIScroll = new AXScroll(); // 스크롤 인스턴스 선언
4325 * myUIScroll.setConfig({
4326 *     targetID:"UIScrollContainer",
4327 *     scrollID:"UIScrollTarget"
4328 * });
4329 *```
4330 *
4331 */
4332var AXScroll = Class.create(AXJ, {
4333    initialize: function (AXJ_super) {
4334        AXJ_super();
4335        this.config.CT_className = "AXScroll";
4336        this.config.ST_className = "scrollTarget";
4337        this.scrollBarMove = false;
4338        this.scrollBarAttr = {};
4339        this.Observer = null;
4340        this.config.yscroll = true;
4341        this.config.xscroll = false;
4342	    this.config.scrollBarMargin = 3;
4343
4344        this.minHeightSB = { TF: false, h: 0 };
4345        this.minWidthSB = { TF: false, w: 0 };
4346    },
4347    /**
4348     * @method AXScroll.setConfig
4349     * @param {Object} configs - 스크롤 속성 오브젝트
4350     * @description 스크롤 대상과 스크롤 컨테이너를 지정하여 스크롤UI를 구현합니다.
4351     * @example
4352     *```js
4353     * myUIScroll.setConfig({
4354     *     targetID:"UIScrollContainer",
4355     *     scrollID:"UIScrollTarget",
4356     *     bounces:true
4357     * });
4358     *```
4359     */
4360    init: function () {
4361        var config = this.config;
4362        if (Object.isUndefined(config.targetID)) {
4363            trace("need targetID - setConfig({targetID:''})");
4364            return;
4365        }
4366        if (Object.isUndefined(config.scrollID)) {
4367            trace("need scrollID - setConfig({scrollID:''})");
4368            return;
4369        }
4370        this.scrollTargetID = axdom("#" + config.targetID);
4371        this.scrollScrollID = axdom("#" + config.scrollID);
4372        this.scrollTargetID.addClass(this.config.CT_className);
4373        this.scrollScrollID.addClass(this.config.ST_className);
4374        this.initScroll();
4375        this.bindEvent();
4376    },
4377    /**
4378     * @method AXScroll.updateScroll
4379     * @returns {AXScroll}
4380     * @description 스크롤 처리 대상의 사이즈를 재정의 합니다. 스크롤 대상의 크기가 변경되었을 때 호출
4381     * @example
4382     * ```js
4383     * myUIScroll.updateScroll();
4384     * myUIScroll.resizeScroll(); // updateScroll과 동일한 기능
4385     * ```
4386     */
4387    updateScroll: function () {
4388        this.initScroll();
4389		return this;
4390    },
4391	resizeScroll: function () {
4392		this.initScroll();
4393		return this;
4394	},
4395    initScroll: function () {
4396        var cfg = this.config, _this = this;
4397        if (!this.scroll) {
4398            var po = [];
4399            if (cfg.yscroll) {
4400                po.push("<div class=\"scrollTrack\" id=\"" + cfg.targetID + "_AX_scrollTrack\"></div>");
4401                po.push("<div class=\"scrollBar\" id=\"" + cfg.targetID + "_AX_scrollBar\"></div>");
4402            } else {
4403                this.scrollTargetID.css({ height: this.scrollScrollID.outerHeight() });
4404                /*
4405                setTimeout(function(){
4406
4407                }, 10);
4408                */
4409            }
4410            if (cfg.xscroll) {
4411                po.push("<div class=\"xscrollTrack\" id=\"" + cfg.targetID + "_AX_xscrollTrack\"></div>");
4412                po.push("<div class=\"xscrollBar\" id=\"" + cfg.targetID + "_AX_xscrollBar\"></div>");
4413            }
4414
4415            this.scrollTargetID.append(po.join(''));
4416            this.scroll = true;
4417
4418            if (cfg.yscroll) {
4419                this.scrollTrack = axdom("#" + cfg.targetID + "_AX_scrollTrack");
4420                this.scrollBar = axdom("#" + cfg.targetID + "_AX_scrollBar");
4421            }
4422            if (cfg.xscroll) {
4423                this.xscrollTrack = axdom("#" + cfg.targetID + "_AX_xscrollTrack");
4424                this.xscrollBar = axdom("#" + cfg.targetID + "_AX_xscrollBar");
4425            }
4426        } else {
4427            if (!cfg.yscroll) {
4428                this.scrollTargetID.css({ height: this.scrollScrollID.outerHeight() });
4429            }
4430        }
4431
4432        var CTheight = this.scrollTargetID.innerHeight();
4433        var CTwidth = this.scrollTargetID.innerWidth();
4434
4435        if (cfg.yscroll) {
4436            this.scrollTrack.css({ height: CTheight - (cfg.scrollBarMargin*2) });
4437        }
4438        if (cfg.xscroll) {
4439            this.xscrollTrack.css({ width: CTwidth - (cfg.scrollBarMargin*2) });
4440        } else {
4441            this.scrollScrollID.css({ width: CTwidth });
4442        }
4443
4444        var Cheight = this.scrollScrollID.outerHeight();
4445        var Cwidth = this.scrollScrollID.outerWidth();
4446
4447        if (cfg.yscroll) {
4448            var SBheight = CTheight * (CTheight - (cfg.scrollBarMargin*2)) / Cheight;
4449	        if(SBheight < 30) SBheight = 30;
4450            this.scrollBar.css({ height: Math.ceil(SBheight) });
4451	        /*
4452            if (SBheight < 30) {
4453                this.minHeightSB.TF = true;
4454                this.minHeightSB.h = SBheight;
4455            }
4456            */
4457            if (CTheight == Cheight || CTheight > Cheight) {
4458                this.scrollTrack.hide();
4459                this.scrollBar.hide();
4460                this.scrollScrollID.css({ top: 0 });
4461            } else {
4462                this.scrollTrack.show();
4463                this.scrollBar.show();
4464            }
4465        }
4466        if (cfg.xscroll) {
4467            var SBwidth = CTwidth * (CTwidth - (cfg.scrollBarMargin*2)) / Cwidth;
4468	        if(SBwidth < 30) SBwidth = 30;
4469            this.xscrollBar.css({ width: Math.ceil(SBwidth) });
4470	        /*
4471            if (SBwidth < 30) {
4472                this.minWidthSB.TF = true;
4473                this.minWidthSB.w = SBwidth;
4474            }
4475            */
4476            if (CTwidth == Cwidth || CTwidth > Cwidth) {
4477                this.xscrollTrack.hide();
4478                this.xscrollBar.hide();
4479            } else {
4480                this.xscrollTrack.show();
4481                this.xscrollBar.show();
4482            }
4483        }
4484    },
4485
4486    bindEvent: function () {
4487        var cfg = this.config;
4488
4489        var CTheight = this.scrollTargetID.innerHeight();
4490        var Cheight = this.scrollScrollID.outerHeight();
4491
4492        if (cfg.xscroll) {
4493            var CTwidth = this.scrollTargetID.innerWidth();
4494            var Cwidth = this.scrollScrollID.outerWidth();
4495        }
4496
4497        /* event 선언자 */
4498        var tractActive = this.tractActive.bind(this);
4499        this.tractActiveBind = function (event) {
4500            tractActive(event);
4501        }
4502        var tractInActive = this.tractInActive.bind(this);
4503        this.tractInActiveBind = function (event) {
4504            tractInActive(event);
4505        }
4506        var cancelEvent = this.cancelEvent.bind(this);
4507        this.cancelEventBind = function (event) {
4508            cancelEvent(event);
4509        }
4510        var SBonMouseDown = this.SBonMouseDown.bind(this);
4511        this.SBonMouseDownBind = function (event) {
4512            SBonMouseDown(event);
4513        }
4514        var SBonMouseMove = this.SBonMouseMove.bind(this);
4515        this.SBonMouseMoveBind = function (event) {
4516            SBonMouseMove(event);
4517        }
4518        var SBonMouseUp = this.SBonMouseUp.bind(this);
4519        this.SBonMouseUpBind = function (event) {
4520            SBonMouseUp(event);
4521        }
4522        this.SBonWheelBind = this.SBonWheel.bind(this);
4523        /* event 선언자 */
4524
4525        this.scrollTargetID.bind("mouseover", this.tractActiveBind);
4526        this.scrollTargetID.bind("mouseout", this.tractInActiveBind);
4527
4528        if (cfg.yscroll) {
4529            this.scrollBar.bind("dragstart", this.cancelEventBind);
4530            this.scrollBar.bind("mousedown", this.SBonMouseDownBind);
4531        }
4532
4533        if (cfg.xscroll) {
4534            var SBonMouseDownX = this.SBonMouseDownX.bind(this);
4535            this.SBonMouseDownXBind = function (event) {
4536                SBonMouseDownX(event);
4537            }
4538            var SBonMouseMoveX = this.SBonMouseMoveX.bind(this);
4539            this.SBonMouseMoveXBind = function (event) {
4540                SBonMouseMoveX(event);
4541            }
4542            var SBonMouseUpX = this.SBonMouseUpX.bind(this);
4543            this.SBonMouseUpXBind = function (event) {
4544                SBonMouseUpX(event);
4545            }
4546
4547            this.xscrollBar.bind("dragstart", this.cancelEventBind);
4548            this.xscrollBar.bind("mousedown", this.SBonMouseDownXBind);
4549        }
4550
4551        var mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
4552        if (document.attachEvent) { //if IE (and Opera depending on user setting)
4553            if (AXgetId(cfg.targetID)) AXgetId(cfg.targetID).attachEvent("on" + mousewheelevt, this.SBonWheelBind);
4554        } else if (document.addEventListener) { //WC3 browsers
4555            if (AXgetId(cfg.targetID)) AXgetId(cfg.targetID).addEventListener(mousewheelevt, this.SBonWheelBind, false);
4556        }
4557        if (document.addEventListener) {
4558            var touchstart = this.touchstart.bind(this);
4559            this.touchstartBind = function () {
4560                touchstart();
4561            };
4562            if (AXgetId(cfg.targetID)){
4563                AXgetId(cfg.targetID).addEventListener("touchstart", this.touchstartBind, false);
4564            }
4565        }
4566    },
4567    tractActive: function (event) {
4568        var cfg = this.config;
4569
4570        if (cfg.yscroll) {
4571            this.scrollBar.addClass("scrollBar_hover");
4572            this.scrollTrack.addClass("scrollTrack_hover");
4573        }
4574
4575        if (cfg.xscroll) {
4576            this.xscrollBar.addClass("xscrollBar_hover");
4577            this.xscrollTrack.addClass("xscrollTrack_hover");
4578        }
4579
4580        if (this.Observer) clearTimeout(this.Observer); //닫기 명령 제거
4581        this.initScroll();
4582    },
4583    tractInActive: function (event) {
4584        var SBonWheelEnd = this.SBonWheelEnd.bind(this);
4585        this.Observer = setTimeout(function () {
4586            SBonWheelEnd();
4587        }, 500);
4588    },
4589    getMousePosition: function (event) {
4590        var config = this.config;
4591        var pos = (this.scrollTrack) ? this.scrollTrack.offset() : { left: 0, top: 0 };
4592        var posx = (this.xscrollTrack) ? this.xscrollTrack.offset() : { left: 0, top: 0 };
4593
4594        var x = (event.pageX - posx.left);
4595        var y = (event.pageY - pos.top);
4596        return { x: x, y: y };
4597    },
4598    getTouchPosition: function (event) {
4599        /* 사용안함. 옵션 */
4600        var config = this.config;
4601        var touch = event.touches[0];
4602        var pos = this.scrollTrack.offset();
4603        if (this.config.touchDirection) {
4604            var x = (touch.pageX - pos.left);
4605            var y = (touch.pageY - pos.top);
4606        } else {
4607            var x = (-touch.pageX - pos.left);
4608            var y = (-touch.pageY - pos.top);
4609        }
4610        return { x: x, y: y };
4611    },
4612
4613
4614    /* touch event init --- s */
4615    touchstart: function (e) {
4616        if (this.touhEndObserver) clearTimeout(this.touhEndObserver);
4617        if (this.touhMoveObserver) clearTimeout(this.touhMoveObserver);
4618
4619        var cfg = this.config;
4620        var touch;
4621        var event = window.event;
4622        touch = event.touches[0];
4623        if (!touch.pageX) return;
4624
4625        this.touchStartXY = {
4626            sTime: ((new Date()).getTime() / 1000),
4627            sTop: this.scrollScrollID.position().top,
4628            sLeft: this.scrollScrollID.position().left,
4629            scrollWidth: this.scrollScrollID.outerWidth(),
4630            scrollHeight: this.scrollScrollID.outerHeight(),
4631            targetWidth: this.scrollTargetID.outerWidth(),
4632            targetHeight: this.scrollTargetID.outerHeight(),
4633            x: touch.pageX,
4634            y: touch.pageY
4635        };
4636
4637        var touchEnd = this.touchEnd.bind(this);
4638        this.touchEndBind = function () {
4639            touchEnd(event);
4640        };
4641        var touchMove = this.touchMove.bind(this);
4642        this.touchMoveBind = function () {
4643            touchMove(event);
4644        };
4645
4646        if (document.removeEventListener) {
4647            document.removeEventListener("touchend", this.touchEndBind, false);
4648            document.removeEventListener("touchmove", this.touchMoveBind, false);
4649        }
4650        if (document.addEventListener) {
4651            document.addEventListener("touchend", this.touchEndBind, false);
4652            document.addEventListener("touchmove", this.touchMoveBind, false);
4653        }
4654
4655        var minLeft = 0;
4656        var maxLeft = - (this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth);
4657        var minTop = 0;
4658        var maxTop = - (this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight);
4659        var scrollPosition = this.scrollScrollID.position();
4660
4661        if((scrollPosition.left < minLeft && scrollPosition.left > maxLeft) || (scrollPosition.top < minTop && scrollPosition.top > maxTop)){
4662            this.scrollScrollID.stop();
4663            if(cfg.yscroll) this.scrollBar.stop();
4664            if(cfg.xscroll) this.xscrollBar.stop();
4665        }
4666
4667        this.tractActive();
4668    },
4669    touchMove: function (e) {
4670        if (this.touhEndObserver) clearTimeout(this.touhEndObserver);
4671        if (this.touhMoveObserver) clearTimeout(this.touhMoveObserver);
4672        var cfg = this.config;
4673
4674        var touch;
4675        var event = window.event;
4676        touch = event.touches[0];
4677        if (!touch.pageX) return;
4678
4679        if ((this.touchStartXY.x - touch.pageX).abs() < (this.touchStartXY.y - touch.pageY).abs()) {
4680            if (cfg.yscroll && this.touchStartXY.scrollHeight > this.touchStartXY.targetHeight) {
4681                this.touchMode = "ns";
4682                var touchDirection = ((this.touchStartXY.y - touch.pageY) <= 0) ? "T" : "B"; /* 위아래 이동 */
4683
4684                if(touchDirection != this.touchDirection){
4685                    this.touchMoveAfter(touch);
4686                }
4687
4688                this.touchDirection = touchDirection;
4689                if(this.moveBlock({top:touch.pageY - this.touchStartXY.y})){
4690                    if (event.preventDefault) event.preventDefault();
4691                    else return false;
4692                }
4693            }
4694        } else if ((this.touchStartXY.x - touch.pageX).abs() > (this.touchStartXY.y - touch.pageY).abs()) {
4695            if (cfg.xscroll && this.touchStartXY.scrollWidth > this.touchStartXY.targetWidth) {
4696                this.touchMode = "we";
4697                var touchDirection = ((this.touchStartXY.x - touch.pageX) <= 0) ? "L" : "R"; /* 좌우 이동 */
4698
4699                if(touchDirection != this.touchDirection){
4700                    this.touchMoveAfter(touch);
4701                }
4702
4703                this.touchDirection = touchDirection;
4704                if(this.moveBlock({left:touch.pageX - this.touchStartXY.x})){
4705                    if (event.preventDefault) event.preventDefault();
4706                    else return false;
4707                }
4708            }
4709        }
4710        if (((this.touchStartXY.x - touch.pageX).abs() - (this.touchStartXY.y - touch.pageY).abs()).abs() < 5) {
4711            //this.touchSelecting = true;
4712        }
4713        var touchMoveAfter = this.touchMoveAfter.bind(this);
4714        this.touhMoveObserver = setTimeout(function () {
4715            touchMoveAfter(touch);
4716        }, 50);
4717    },
4718    touchMoveAfter: function(touch){
4719        try{
4720            this.touchStartXY.sTime = ((new Date()).getTime() / 1000);
4721            this.touchStartXY.sTop = this.scrollScrollID.position().top;
4722            this.touchStartXY.sLeft = this.scrollScrollID.position().left;
4723            this.touchStartXY.x = touch.pageX;
4724            this.touchStartXY.y = touch.pageY;
4725        }catch(e){
4726            //trace(e);
4727        }
4728    },
4729    touchEnd: function (e) {
4730        var cfg = this.config;
4731        var event = window.event || e;
4732        //this.moveSens = 0;
4733        //this.touchMode = false;
4734
4735        if (document.removeEventListener) {
4736            document.removeEventListener("touchend", this.touchEndBind, false);
4737            document.removeEventListener("touchmove", this.touchMoveBind, false);
4738        }
4739
4740        var moveEndBlock = this.moveEndBlock.bind(this);
4741        if(this.touchStartXY){
4742            this.touhEndObserver = setTimeout(function () {
4743                moveEndBlock();
4744            }, 10);
4745        }
4746    },
4747    moveBlock: function(moveXY){
4748        var cfg = this.config;
4749        var returnTF = true;
4750        if(moveXY.left != undefined){
4751            var newLeft = (this.touchStartXY.sLeft + (moveXY.left));
4752            var minLeft = 0;
4753            var maxLeft = - (this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth);
4754            if(cfg.bounces){
4755                minLeft = this.touchStartXY.targetWidth * 0.4;
4756                maxLeft = -((this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth) * 1.2);
4757            }
4758            if(newLeft > minLeft){
4759                newLeft = minLeft;
4760                returnTF = false;
4761            }else if(newLeft < maxLeft){
4762                newLeft = maxLeft;
4763                returnTF = false;
4764            }
4765            this.scrollScrollID.css({left: newLeft});
4766            this.setScrollbarPositionForWheel("left");
4767        }else if(moveXY.top != undefined){
4768            var newTop = (this.touchStartXY.sTop + (moveXY.top));
4769            var minTop = 0;
4770            var maxTop = - (this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight);
4771            if(cfg.bounces){
4772                minTop = this.touchStartXY.targetHeight * 0.4;
4773                maxTop = -((this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight) * 1.2);
4774            }
4775            if(newTop > minTop){
4776                newTop = minTop;
4777                returnTF = false;
4778            }else if(newTop < maxTop){
4779                newTop = maxTop;
4780                returnTF = false;
4781            }
4782            this.scrollScrollID.css({top: newTop});
4783            this.setScrollbarPositionForWheel("top");
4784        }
4785        /*trace(moveXY);*/
4786        return returnTF;
4787        //return true;
4788    },
4789    moveEndBlock: function(){
4790	    var cfg = this.config;
4791        /* 관성발동여부 체크 */
4792        if(!this.touchStartXY) return;
4793        var sTime = this.touchStartXY.sTime;
4794        var eTime = ((new Date()).getTime() / 1000);
4795        var dTime = eTime - sTime;
4796        //var setScrollbarPositionForWheel = this.setScrollbarPositionForWheel.bind(this);
4797        var tractInActive = this.tractInActive.bind(this);
4798
4799        if(this.touchMode == "we"){ /* 좌우 */
4800            if (this.touchStartXY.scrollWidth <= this.touchStartXY.targetWidth) return;
4801            var eLeft = this.scrollScrollID.position().left;
4802            var dLeft = eLeft - this.touchStartXY.sLeft;
4803            var velocityLeft = Math.ceil((dLeft/dTime)/1); // 속력= 거리/시간
4804            var endLeft = Math.ceil(eLeft + velocityLeft); //스크롤할때 목적지
4805            if(endLeft > 0) endLeft = 0;
4806            else if(endLeft < - (this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth)){
4807                endLeft = - (this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth);
4808            }
4809            var newLeft = endLeft.abs();
4810            this.touchStartXY.sLeft = -newLeft;
4811            this.scrollScrollID.animate({left: -newLeft}, (eLeft + newLeft).abs(), "circOut", function () {
4812                tractInActive();
4813            });
4814            this.setScrollbarPositionForWheel("left", (eLeft + newLeft).abs(), "circOut", {left: -newLeft});
4815
4816            if (cfg.yscroll){
4817                var eTop = this.scrollScrollID.position().top;
4818                var topChange = false;
4819                if(eTop > 0){
4820                    eTop = 0;
4821                    topChange = true;
4822                }else if(eTop < - (this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight)){
4823                    eTop = (this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight);
4824                    topChange = true;
4825                }
4826                if(topChange) this.scrollScrollID.css({top: -eTop});
4827            }
4828
4829        }else{ /* 위아래 */
4830            if (this.touchStartXY.scrollHeight <= this.touchStartXY.targetHeight) return;
4831            var eTop = this.scrollScrollID.position().top;
4832            var dTop = eTop - this.touchStartXY.sTop;
4833            var velocityTop = Math.ceil((dTop/dTime)/1); // 속력= 거리/시간
4834            var endTop = Math.ceil(eTop + velocityTop); //스크롤할때 목적지
4835            if(endTop > 0) endTop = 0;
4836            else if(endTop < - (this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight)){
4837                endTop = - (this.touchStartXY.scrollHeight - this.touchStartXY.targetHeight);
4838            }
4839
4840            var newTop = endTop.abs();
4841            this.touchStartXY.sTop = -newTop;
4842            this.scrollScrollID.animate({top: -newTop}, (eTop + newTop).abs(), "circOut", function () {
4843                tractInActive();
4844            });
4845            this.setScrollbarPositionForWheel("top", (eTop + newTop).abs(), "circOut", {top: -newTop});
4846
4847            if (cfg.xscroll){
4848                var eLeft = this.scrollScrollID.position().left;
4849                var leftChange = false;
4850                if(eLeft > 0){
4851                    eLeft = 0;
4852                    leftChange = true;
4853                }else if(eLeft < - (this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth)){
4854                    eLeft = (this.touchStartXY.scrollWidth - this.touchStartXY.targetWidth);
4855                    leftChange = true;
4856                }
4857                if(leftChange) this.scrollScrollID.css({left: -eLeft});
4858            }
4859        }
4860        this.touchStartXY = null;
4861
4862    },
4863    /* touch event init --- e */
4864
4865
4866    /* scrollBar event */
4867    SBonMouseDown: function (event) {
4868        var config = this.config;
4869        this.scrollBarMove = true;
4870        var pos = this.getMousePosition(event);
4871        var SBpos = this.scrollBar.position();
4872        var SBh = this.scrollBar.height();
4873        var STh = this.scrollTrack.height();
4874        var Ch = this.scrollScrollID.outerHeight();
4875
4876        this.Ch = Ch;
4877        this.STh = STh;
4878
4879        this.scrollBarAttr = { x: (SBpos.left - pos.x).number(), y: (SBpos.top - pos.y).number(), h: SBh.number(), sth: STh };
4880        //trace("y:"+SBpos.top +" - "+ pos.y +", h:"+ SBh +", sth:"+STh+", calc y : "+(SBpos.top - pos.y).number());
4881
4882        axdom(document.body).bind("mousemove.AXScroll", this.SBonMouseMoveBind);
4883        axdom(document.body).bind("mouseup.AXScroll", this.SBonMouseUpBind);
4884        axdom(document.body).bind("mouseleave.AXScroll", this.SBonMouseUpBind);
4885    },
4886    SBonMouseMove: function (event) {
4887        var config = this.config;
4888        if (this.scrollBarMove) {
4889            axdom(document.body).attr("onselectstart", "return false");
4890            //axdom(document.body).addClass("AXUserSelectNone");
4891            var pos = this.getMousePosition(event);
4892
4893            var SBy = pos.y + this.scrollBarAttr.y;
4894            //trace(SBy +" = "+ pos.y +"+"+ this.scrollBarAttr.y);
4895
4896            if (SBy < config.scrollBarMargin) SBy = config.scrollBarMargin;
4897            if ((SBy + this.scrollBarAttr.h) > this.scrollBarAttr.sth) {
4898                SBy = this.scrollBarAttr.sth - this.scrollBarAttr.h + config.scrollBarMargin;
4899                //trace(SBy)
4900            }
4901            this.scrollBar.css({ top: SBy });
4902            this.setContentPosition();
4903        }
4904    },
4905    SBonMouseUp: function (event) {
4906        if (this.scrollBarMove) {
4907            var config = this.config;
4908            this.scrollBarMove = false;
4909            axdom(document.body).removeAttr("onselectstart");
4910            //axdom(document.body).removeClass("AXUserSelectNone");
4911        }
4912        axdom(document.body).unbind("mousemove.AXScroll");
4913        axdom(document.body).unbind("mouseup.AXScroll");
4914        axdom(document.body).unbind("mouseleave.AXScroll");
4915    },
4916
4917    SBonMouseDownX: function (event) {
4918        var config = this.config;
4919        this.scrollBarMove = true;
4920        var pos = this.getMousePosition(event);
4921        var SBpos = this.xscrollBar.position();
4922        var SBw = this.xscrollBar.width();
4923        var STw = this.xscrollTrack.width();
4924        var Cw = this.scrollScrollID.outerWidth();
4925
4926        this.Cw = Cw;
4927        this.STw = STw;
4928
4929        this.scrollBarAttr = { x: (SBpos.left - pos.x).number(), w: SBw.number(), stw: STw };
4930
4931        axdom(document.body).bind("mousemove.AXScroll", this.SBonMouseMoveXBind);
4932        axdom(document.body).bind("mouseup.AXScroll", this.SBonMouseUpXBind);
4933        axdom(document.body).bind("mouseleave.AXScroll", this.SBonMouseUpXBind);
4934    },
4935    SBonMouseMoveX: function (event) {
4936        var config = this.config;
4937        if (this.scrollBarMove) {
4938
4939            axdom(document.body).attr("onselectstart", "return false");
4940            //axdom(document.body).addClass("AXUserSelectNone");
4941            var pos = this.getMousePosition(event);
4942
4943            var SBx = pos.x + this.scrollBarAttr.x;
4944            //trace(SBy +" = "+ pos.y +"+"+ this.scrollBarAttr.y);
4945
4946            if (SBx < config.scrollBarMargin) SBx = config.scrollBarMargin;
4947            if ((SBx + this.scrollBarAttr.w) > this.scrollBarAttr.stw) {
4948                SBx = this.scrollBarAttr.stw - this.scrollBarAttr.w + config.scrollBarMargin;
4949            }
4950
4951            this.xscrollBar.css({ left: SBx });
4952            this.setContentPosition("xscroll");
4953        }
4954    },
4955    SBonMouseUpX: function (event) {
4956        if (this.scrollBarMove) {
4957            var config = this.config;
4958            this.scrollBarMove = false;
4959            axdom(document.body).removeAttr("onselectstart");
4960            //axdom(document.body).removeClass("AXUserSelectNone");
4961        }
4962        axdom(document.body).unbind("mousemove.AXScroll");
4963        axdom(document.body).unbind("mouseup.AXScroll");
4964        axdom(document.body).unbind("mouseleave.AXScroll");
4965    },
4966
4967    SBonWheel: function (e) {
4968        //content top handle
4969        var config = this.config;
4970
4971        var event = (window.event || e);
4972        var delta = event.detail ? event.detail * (-10) : event.wheelDelta; //check for detail first so Opera uses that instead of wheelDelta
4973
4974        var Sy = this.scrollScrollID.position().top;
4975        var Sh = this.scrollScrollID.outerHeight();
4976        var TGh = this.scrollTargetID.height();
4977
4978        //trace(Sh+" + "+Sy+" < "+TGh );
4979        if (Sh < TGh) return; //스크롤 할 대상이 없음 2013-02-08 오후 5:48:07 [email protected]
4980
4981        var eventCancle = false;
4982        Sy += delta;
4983        if (Sy > 0) {
4984            Sy = 0;
4985            eventCancle = true;
4986        }
4987
4988        //trace(Sh+" + "+Sy+" < "+TGh );
4989
4990        if ((Sh + Sy) < TGh) {
4991            Sy = (TGh - Sh);
4992            eventCancle = true;
4993        }
4994        this.scrollScrollID.css({ top: Sy });
4995
4996        //this.setContentPosition();
4997        this.setScrollbarPositionForWheel("top");
4998
4999        if (!eventCancle) {
5000            if (event.preventDefault) event.preventDefault();
5001            if (event.stopPropagation) event.stopPropagation();
5002            event.cancelBubble = true;
5003            return false;
5004        }
5005
5006    },
5007    SBonWheelEnd: function () {
5008        if (this.scrollBarMove) return;
5009        var config = this.config;
5010
5011        if (config.yscroll) {
5012            this.scrollBar.removeClass("scrollBar_hover");
5013            this.scrollTrack.removeClass("scrollTrack_hover");
5014        }
5015
5016        if (config.xscroll) {
5017            this.xscrollBar.removeClass("xscrollBar_hover");
5018            this.xscrollTrack.removeClass("xscrollTrack_hover");
5019        }
5020
5021    },
5022    cancelEvent: function (event) {
5023        event.stopPropagation(); // disable  event
5024        return false;
5025    },
5026    setContentPosition: function (xscroll) {
5027        var config = this.config;
5028
5029        if (xscroll == "xscroll") {
5030
5031	        if (!this.contentScrollXAttr) {
5032		        this.contentScrollXAttr = {
5033			        bodyWidth: this.scrollTargetID.width(),
5034			        scrollWidth: this.scrollScrollID.width(),
5035			        scrollTrackXWidth: this.xscrollTrack.width(),
5036			        scrollXHandleWidth: this.xscrollBar.width()
5037		        };
5038	        }else{
5039		        // scrollContent height update
5040		        this.contentScrollXAttr.scrollWidth = this.scrollScrollID.width();
5041		        this.contentScrollXAttr.scrollTrackXWidth = this.xscrollTrack.width();
5042		        this.contentScrollXAttr.scrollXHandleWidth = this.xscrollBar.width();
5043	        }
5044
5045            var SBx = this.xscrollBar.position().left - config.scrollBarMargin;
5046	        var L = (this.contentScrollXAttr.scrollWidth * (SBx) / this.contentScrollXAttr.scrollTrackXWidth).round(0);
5047            this.scrollScrollID.css({ left: -L });
5048
5049        } else {
5050
5051	        if (!this.contentScrollYAttr) {
5052		        this.contentScrollYAttr = {
5053			        bodyHeight: this.scrollTargetID.height(),
5054			        scrollHeight: this.scrollScrollID.height(),
5055			        scrollTrackYHeight: this.scrollTrack.height(),
5056			        scrollYHandleHeight: this.scrollBar.height()
5057		        };
5058	        }else{
5059		        // scrollContent height update
5060		        this.contentScrollYAttr.scrollHeight = this.scrollScrollID.height();
5061		        this.contentScrollYAttr.scrollTrackYHeight = this.scrollTrack.height();
5062		        this.contentScrollYAttr.scrollYHandleHeight = this.scrollBar.height();
5063	        }
5064
5065            var SBy = this.scrollBar.position().top - config.scrollBarMargin;
5066	        var T = (this.contentScrollYAttr.scrollHeight - this.contentScrollYAttr.bodyHeight) * ( (SBy) / (this.contentScrollYAttr.scrollTrackYHeight - this.contentScrollYAttr.scrollYHandleHeight) ).number();
5067            this.scrollScrollID.css({ top: -T });
5068        }
5069
5070    },
5071
5072    setScrollbarPositionForWheel: function (direction, duration, easing, position) {
5073        //scrollbar top position handle for wheel
5074        var config = this.config;
5075
5076        if(direction == "left"){
5077
5078	        if (!this.contentScrollXAttr) {
5079		        this.contentScrollXAttr = {
5080			        bodyWidth: this.scrollTargetID.width(),
5081			        scrollWidth: this.scrollScrollID.width(),
5082			        scrollTrackXWidth: this.xscrollTrack.width(),
5083			        scrollXHandleWidth: this.scrollBar.outerWidth()
5084		        };
5085	        }else{
5086		        // scrollContent height update
5087		        this.contentScrollXAttr.scrollWidth = this.scrollScrollID.width();
5088		        this.contentScrollXAttr.scrollTrackXWidth = this.xscrollTrack.width();
5089		        this.contentScrollXAttr.scrollXHandleWidth = this.xscrollBar.outerWidth();
5090	        }
5091
5092	        var Sy = (position) ? position.left : this.scrollScrollID.position().left;
5093	        var L = (this.contentScrollXAttr.scrollTrackXWidth - this.contentScrollXAttr.scrollXHandleWidth) * ((Sy) / (this.contentScrollXAttr.scrollWidth - this.contentScrollXAttr.bodyWidth));
5094	        L -= config.scrollBarMargin;
5095	        if(easing){
5096                this.xscrollBar.animate({
5097                    left: -L
5098                    //,width: Math.ceil(this.scrollTargetID.outerWidth() * (this.scrollTargetID.outerWidth() - 4) / (this.scrollScrollID.outerWidth() + addY))
5099                }, duration, easing, function () {});
5100            }else{
5101                this.xscrollBar.css({
5102                    left: -L
5103                    //,width: Math.ceil(this.scrollTargetID.outerWidth() * (this.scrollTargetID.outerWidth() - 4) / (this.scrollScrollID.outerWidth() + addY))
5104                });
5105            }
5106        }else{
5107
5108            if (!config.yscroll) return false;
5109            //wheel control event is not jquery event !
5110
5111	        if (!this.contentScrollYAttr) {
5112		        this.contentScrollYAttr = {
5113			        bodyHeight: this.scrollTargetID.height(),
5114			        scrollHeight: this.scrollScrollID.height(),
5115			        scrollTrackYHeight: this.scrollTrack.height(),
5116			        scrollYHandleHeight: this.scrollBar.outerHeight()
5117		        };
5118	        }else{
5119		        // scrollContent height update
5120		        this.contentScrollYAttr.scrollHeight = this.scrollScrollID.height();
5121		        this.contentScrollYAttr.scrollTrackYHeight = this.scrollTrack.height();
5122		        this.contentScrollYAttr.scrollYHandleHeight = this.scrollBar.outerHeight();
5123	        }
5124
5125	        var Sy = (position) ? position.top : this.scrollScrollID.position().top;
5126	        var T = (this.contentScrollYAttr.scrollTrackYHeight - this.contentScrollYAttr.scrollYHandleHeight) * ((Sy) / (this.contentScrollYAttr.scrollHeight - this.contentScrollYAttr.bodyHeight));
5127			T -= config.scrollBarMargin;
5128            if(easing){
5129                //trace({ top: SBy }, duration, easing);
5130
5131                this.scrollBar.animate({
5132                    top: -T
5133                    //,height: Math.ceil(this.scrollTargetID.outerHeight() * (this.scrollTargetID.outerHeight() - 4) / (this.scrollScrollID.outerHeight() + addY))
5134                }, duration, easing, function () {});
5135            }else{
5136                this.scrollBar.css({
5137                    top: -T
5138                    //,height: Math.ceil(this.scrollTargetID.outerHeight() * (this.scrollTargetID.outerHeight() - 4) / (this.scrollScrollID.outerHeight() + addY))
5139                });
5140            }
5141
5142        }
5143    },
5144
5145
5146    setSBPosition: function () {
5147        var config = this.config;
5148	    try {
5149
5150		    var Ctop = this.scrollScrollID.position().top;
5151		    var CTheight = this.scrollTargetID.innerHeight();
5152		    var STh = this.scrollTrack.height();
5153		    var Ch = this.scrollScrollID.outerHeight();
5154
5155		    var SBh = this.scrollBar.height();
5156
5157		    //trace({Ctop:Ctop, CTheight:CTheight, Ch:Ch, STh:STh, SBh:SBh, x:(STh*Ctop)/Ch});
5158		    var SBtop = -(STh * Ctop) / Ch;
5159		    if (SBtop < config.scrollBarMargin) SBtop = config.scrollBarMargin;
5160		    if ((SBtop + SBh) > STh) {
5161			    SBtop = STh - SBh + config.scrollBarMargin;
5162		    }
5163		    this.scrollBar.css({ top: SBtop });
5164	    }catch(e){
5165
5166	    }
5167    },
5168    /**
5169     * @method AXScroll.focusElement
5170     * @param {String} id - 포커스 할 대상 엘리먼트 아이디
5171     * @returns {AXScroll}
5172     * @description 스크롤 오브젝트 안에 엘리먼트를 포커스 합니다.
5173     * @example
5174     *```js
5175     * myUIScroll.focusElement("resizer01");
5176     *```
5177     */
5178    focusElement: function (id) {
5179        var config = this.config;
5180        if (AXgetId(id)) {
5181            //trace(axdom("#"+id).position());
5182	        var ppos = this.scrollScrollID.offset();
5183            var pos = axdom("#" + id).offset();
5184
5185            var myNewTop = pos.top - ppos.top;
5186            var CTheight = this.scrollTargetID.innerHeight();
5187            var Cheight = this.scrollScrollID.outerHeight();
5188            if ((Cheight - myNewTop) < CTheight) {
5189                myNewTop = Cheight - CTheight;
5190            }
5191            if (myNewTop < 0) myNewTop = 0;
5192            this.scrollScrollID.css({ top: -myNewTop });
5193            this.setSBPosition();
5194        }
5195		return this;
5196    },
5197    /**
5198     * @method AXScroll.scrollTop
5199     * @param {Number} top - scrollTop position
5200     * @returns {AXScroll}
5201     * @description 스크롤 포지션을 원하는 포지션으로 이동합니다.
5202     * @example
5203     *```js
5204     * myUIScroll.scrollTop(0);
5205     *```
5206     */
5207    scrollTop: function (top) {
5208        var myNewTop = top;
5209        var CTheight = this.scrollTargetID.innerHeight();
5210        var Cheight = this.scrollScrollID.outerHeight();
5211        if ((Cheight - myNewTop) < CTheight) {
5212            myNewTop = Cheight - CTheight;
5213        }
5214        if (myNewTop < 0) myNewTop = 0;
5215        this.scrollScrollID.css({ top: -myNewTop });
5216        this.setSBPosition();
5217		return this;
5218    },
5219    /**
5220     * @method AXScroll.moveTo
5221     * @param {Number} x - scrollTop position (optional)
5222     * @param {Number} y - scrollLeft position (optional)
5223     * @returns {AXScroll}
5224     * @description 스크롤위치를 이동시킵니다.
5225     * @example
5226     *```js
5227     * myUIScroll.moveTo();
5228     *```
5229     */
5230    moveTo: function (x, y) {
5231        var cfg = this.config;
5232        var css = {};
5233        if (!AXUtil.isEmpty(x)) {
5234            css.left = -x;
5235        }
5236        if (!AXUtil.isEmpty(y)) {
5237            css.top = -y;
5238        }
5239
5240        this.scrollScrollID.css(css);
5241        if (cfg.yscroll && !AXUtil.isEmpty(css.top)) {
5242            this.scrollBar.css({ top: css.top });
5243        }
5244        if (cfg.xscroll && !AXUtil.isEmpty(css.left)) {
5245            this.xscrollBar.css({ left: css.left });
5246        }
5247		return this;
5248    },
5249    /**
5250     * @method AXScroll.unbind
5251     * @returns {AXScroll}
5252     * @description 스크롤을 UI를 제거합니다.
5253     * @example
5254     * ```js
5255     * myUIScroll.unbind();
5256     * ```
5257     */
5258    unbind: function () {
5259        var config = this.config;
5260        this.scroll = false;
5261
5262        this.scrollTrack.remove();
5263        this.scrollBar.remove();
5264
5265        this.scrollTargetID.unbind("mouseover", this.tractActiveBind);
5266        this.scrollTargetID.unbind("mouseout", this.tractInActiveBind);
5267
5268        //axdom("#"+config.targetID+"_AX_scrollBar").unbind("dragstart", this.cancelEventBind);
5269        //axdom("#"+config.targetID+"_AX_scrollBar").unbind("mousedown", this.SBonMouseDownBind);
5270        axdom(document.body).unbind("mousemove.AXScroll", this.SBonMouseMoveBind);
5271        axdom(document.body).unbind("mouseup.AXScroll", this.SBonMouseUpBind);
5272
5273        var mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel";
5274        if (document.attachEvent) { //if IE (and Opera depending on user setting)
5275            if (AXgetId(config.targetID)) AXgetId(config.targetID).detachEvent("on" + mousewheelevt, this.SBonWheelBind);
5276        } else if (document.addEventListener) { //WC3 browsers
5277            if (AXgetId(config.targetID)) AXgetId(config.targetID).removeEventListener(mousewheelevt, this.SBonWheelBind, false);
5278        }
5279
5280        if (document.addEventListener) {
5281            if (AXgetId(config.targetID)) AXgetId(config.targetID).removeEventListener("touchstart", this.SBtouchstartBind, false)
5282        }
5283		return this;
5284    }
5285});
5286/* ---------------------------------------------- AXScroll -- */
5287
5288/* -- AXCalendar ---------------------------------------------- */
5289/**
5290 * @class AXCalendar
5291 * @extends AXJ
5292 * @version v1.2
5293 * @author [email protected]
5294 * @logs
5295 * "2012-12-05 오후 11:54:27"
5296 * "2014-03-31 오후 4:53:02 - tom : timePage PM 이면 12시 선택 못하도록 기능 변경"
5297 * "2015-03-17 tom : 0시 0분 입력 가능 하도록 수정"
5298 *
5299 */
5300var AXCalendar = Class.create(AXJ, {
5301    /**
5302     * AXCalendar 기본속성
5303     * @member {Object} AXCalendar.config
5304     * @example
5305     *```js
5306     * {
5307     *     CT_className : {String},
5308     *     weeks : {
5309     *        { name: "SUN" },
5310     *        { name: "MON" },
5311     *        { name: "TUE" },
5312     *        { name: "WED" },
5313     *        { name: "THU" },
5314     *        { name: "FRI" },
5315     *        { name: "SAT" }
5316     *     },
5317     *     printFormat : "dd",
5318     *     titleFormat : "yyyy/mm/dd",
5319     *     valueFormat : "yyyy-mm-dd"
5320     * }
5321     *```
5322     */
5323    initialize: function (AXJ_super) {
5324        AXJ_super();
5325        this.config.CT_className = "AXCalendar";
5326        this.Observer = null;
5327        this.config.weeks = [
5328            { name: "SUN" },
5329            { name: "MON" },
5330            { name: "TUE" },
5331            { name: "WED" },
5332            { name: "THU" },
5333            { name: "FRI" },
5334            { name: "SAT" }
5335        ];
5336        this.config.printFormat = "dd";
5337        this.config.titleFormat = "yyyy/mm/dd";
5338        this.config.valueFormat = "yyyy-mm-dd";
5339    },
5340    /**
5341     * @method AXCalendar.setConfig
5342     * @param {Object} config
5343     * @description 선언된 스크롤 클래스를 사용하기 위해 속성을 정의합니다.
5344     * @example
5345     *```js
5346     * mycalendar.setConfig(config);
5347     *
5348     * var config = {
5349     *     CT_className : {String},
5350     *     weeks : {Object} [{ { name: "SUN" }, { name: "MON" }, { name: "TUE" }, { name: "WED" }, { name: "THU" }, { name: "FRI" }, { name: "SAT" } }],
5351     *     printFormat : {String} [dd],
5352     *     titleFormat : {String} [yyyy/mm/dd],
5353     *     valueFormat : {String} [yyyy-mm-dd]
5354     * };
5355     *```
5356     */
5357    init: function () {
5358
5359    },
5360    getBasicDate: function () {
5361        var cfg = this.config;
5362        if (cfg.basicDate != undefined) {
5363            return cfg.basicDate.date();
5364        } else {
5365            return new Date();
5366        }
5367    },
5368    getCalendarStartDate: function (date) {
5369        var cfg = this.config;
5370        var calendarStartDate, monthStartDate, basicDate;
5371        basicDate = (date) ? date.date() : this.getBasicDate();
5372        monthStartDate = new Date(basicDate.getFullYear(), basicDate.getMonth(), 1, 12);
5373        var calendarStartDateDay = monthStartDate.getDay();
5374        if (calendarStartDateDay == 0) calendarStartDateDay = 7;
5375        calendarStartDate = monthStartDate.add(-calendarStartDateDay);
5376        return { calendarStartDate: calendarStartDate, monthStartDate: monthStartDate };
5377    },
5378    /**
5379     * @method AXCalendar.printDayPage
5380     * @param {String} [toDay]
5381     * @returns {AXCalendar}
5382     * @description 일자 캘린더를 targetID 안에 출력합니다
5383     * @example
5384     *```js
5385     * mycalendar.printDayPage("2014-11-01");
5386     *```
5387     */
5388    printDayPage: function (date) {
5389        var cfg = this.config;
5390
5391        if (Object.isUndefined(cfg.targetID)) {
5392            trace("need targetID - setConfig({targetID:''})");
5393            return;
5394        }
5395
5396        var calendarDate = this.getCalendarStartDate(date);
5397        var calendarStartDate = calendarDate.calendarStartDate;
5398        var monthStartDate = calendarDate.monthStartDate;
5399        var basicDate = this.getBasicDate();
5400        var setDate = (date) ? date.date() : new Date();
5401        //
5402        var po = [];
5403        po.push("<div id=\"" + cfg.targetID + "_AX_box\" class=\"" + cfg.CT_className + "\">");
5404        po.push("<table cellspacing=\"0\" cellpadding=\"0\" class=\"calendarPage\">");
5405        po.push("<thead>");
5406        po.push("<tr>");
5407        axf.each(cfg.weeks, function (wi, ww) {
5408            po.push("<td class=\"head_" + wi + " dayofweek_" + wi + "\">" + ww.name + "</td>");
5409        });
5410        po.push("</tr>");
5411        po.push("</thead>");
5412        po.push("<tbody>");
5413
5414        var minTime = -1;
5415        var maxTime = -1;
5416        var onBeforeShowDay;
5417        var roopDate = calendarStartDate;
5418        if (cfg.minDate) { minTime = cfg.minDate.date().getTime(); }
5419        if (cfg.maxDate) { maxTime = cfg.maxDate.date().getTime(); }
5420        if (cfg.onBeforeShowDay) { onBeforeShowDay = cfg.onBeforeShowDay.bind(this); }
5421        var i = 0; while (i < 6) {
5422            po.push("<tr>");
5423            var k = 0; while (k < 7) {
5424                var roopTime = roopDate.getTime();
5425                var dayValue = roopDate.print(this.config.printFormat);
5426                var addClass = [];
5427                var addStyle = "";
5428                var tdClass = [];
5429                var printTitle = roopDate.print(this.config.titleFormat);
5430                var isEnable = true;
5431                if (onBeforeShowDay) {
5432                    var addData = onBeforeShowDay(roopDate); // addData -> { isEnable: true|false, title:'성탄절', className: 'holyday', style: 'color:red' }
5433                    if (addData) {
5434                        if (addData.className) { addClass.push(addData.className); } // ie7 이하에서 class 예약어라 사용안됨
5435                        if (addData.style) { addStyle = addData.style; }
5436                        if (addData.title) { printTitle = addData.title; }
5437                        if (addData.isEnable === false) { isEnable = false; }
5438                    }
5439                }
5440                if (isEnable && minTime > -1) { isEnable = !(roopTime < minTime); }
5441                if (isEnable && maxTime > -1) { isEnable = !(roopTime > maxTime); }
5442                if (roopDate.getMonth() != monthStartDate.getMonth()) addClass.push("notThisMonth");
5443                if (setDate.diff(roopDate, "D") == 0) tdClass.push("setDate");
5444                if (!isEnable) { addClass.push("disabled"); }
5445                po.push("<td class=\"bodyCol_" + k + " bodyRow_" + i + " " + tdClass.join(" ") + "\"><a " + cfg.href + " class=\"calendarDate " + addClass.join(" ") + "\" id=\"" + cfg.targetID + "_AX_" + roopDate.print(this.config.valueFormat) + "_AX_date\" title=\"" + printTitle + "\">" + dayValue.number() + "</a></td>");
5446                k++;
5447                roopDate = roopDate.add(1);
5448            }
5449            po.push("</tr>");
5450            i++;
5451        }
5452        po.push("</tbody>");
5453        po.push("</table>");
5454        po.push("</div>");
5455        axdom("#" + cfg.targetID).html(po.join(''));
5456		return this;
5457    },
5458    /**
5459     * @method AXCalendar.dayPageSetDay
5460     * @param {Date} - 날짜
5461     * @returns {AXCalendar}
5462     * @description 일자달력의 표시 날짜를 변경합니다.
5463     * @example
5464     *```js
5465     * var myDate = new Date();
5466     * // var myDate = "2014-11-01".date();
5467     * mycalendar.dayPageSetDay(myDate);
5468     *```
5469     */
5470    dayPageSetDay: function (date) {
5471        var cfg = this.config;
5472        axdom("#" + cfg.targetID).find(".calendarDate").removeClass("selected");
5473        axdom("#" + cfg.targetID + "_AX_" + date.print(this.config.valueFormat) + "_AX_date").addClass("selected");
5474		return this;
5475    },
5476    /**
5477     * @method AXCalendar.printMonthPage
5478     * @param {String} [toDay]
5479     * @returns {AXCalendar}
5480     * @description 월 선택 캘린더를 targetID 안에 출력합니다.
5481     * @example
5482     *```js
5483     * mycalendar.printMonthPage("2014-11-01");
5484     *```
5485     */
5486    printMonthPage: function (date) {
5487        var cfg = this.config;
5488        if (Object.isUndefined(cfg.targetID)) {
5489            trace("need targetID - setConfig({targetID:''})");
5490            return;
5491        }
5492        var setDate = (date) ? date.date() : new Date();
5493        //alert(setDate);
5494        var po = [];
5495        po.push("<div id=\"" + cfg.targetID + "_AX_box\" class=\"" + cfg.CT_className + "\">");
5496        po.push("<table cellspacing=\"0\" cellpadding=\"0\" class=\"calendarPageMonth\">");
5497        po.push("<tbody>");
5498
5499        var m = 1;
5500        var i = 0; while (i < 4) {
5501            po.push("<tr>");
5502            var k = 0; while (k < 3) {
5503                var tdClass = [];
5504                if (m == (setDate.getMonth() + 1)) tdClass.push("setDate");
5505                po.push("<td class=\"bodyCol_" + k + " bodyRow_" + i + " " + tdClass.join(" ") + "\"><a " + cfg.href + " class=\"calendarMonth\" id=\"" + cfg.targetID + "_AX_" + m + "_AX_month\" title=\"\">" + m + "월</a></td>");
5506                k++;
5507                m++;
5508            }
5509            po.push("</tr>");
5510            i++;
5511        }
5512        po.push("</tbody>");
5513        po.push("</table>");
5514        po.push("</div>");
5515        axdom("#" + cfg.targetID).html(po.join(''));
5516		return this;
5517    },
5518    /**
5519     * @method AXCalendar.monthPageSetMonth
5520     * @param {Date} - 날짜
5521     * @returns {AXCalendar}
5522     * @description 월달력의 표시 날짜를 변경합니다.
5523     * @example
5524     *```js
5525     * var myDate = new Date();
5526     * // var myDate = "2014-11-01".date();
5527     * mycalendar.monthPageSetMonth(myDate);
5528     *```
5529     */
5530    monthPageSetMonth: function (date) {
5531        var cfg = this.config;
5532        axdom("#" + cfg.targetID).find(".calendarMonth").removeClass("selected");
5533        axdom("#" + cfg.targetID + "_AX_" + (date.getMonth() + 1) + "_AX_month").addClass("selected");
5534    },
5535    /**
5536     * @method AXCalendar.printYearPage
5537     * @param {(String|Number)}
5538     * @returns {AXCalendar}
5539     * @description 년도 선택 캘린더를 targetID 안에 출력합니다.
5540     * @example
5541     *```js
5542     * mycalendar.printYearPage("2014");
5543     * mycalendar.printYearPage(2014);
5544     *```
5545     */
5546    printYearPage: function (year) {
5547        var cfg = this.config;
5548        if (Object.isUndefined(cfg.targetID)) {
5549            trace("need targetID - setConfig({targetID:''})");
5550            return;
5551        }
5552        var po = [];
5553        po.push("<div id=\"" + cfg.targetID + "_AX_box\" class=\"" + cfg.CT_className + "\">");
5554        po.push("<table cellspacing=\"0\" cellpadding=\"0\" class=\"calendarPageMonth\">");
5555        po.push("<tbody>");
5556
5557        var m = year - 4;
5558        var i = 0; while (i < 4) {
5559            po.push("<tr>");
5560            var k = 0; while (k < 3) {
5561                var tdClass = [];
5562                if (m == year) tdClass.push("setDate");
5563                po.push("<td class=\"bodyCol_" + k + " bodyRow_" + i + " " + tdClass.join(" ") + "\"><a " + cfg.href + " class=\"calendarMonth\" id=\"" + cfg.targetID + "_AX_" + m + "_AX_year\" title=\"\">" + m + "년</a></td>");
5564                k++;
5565                m++;
5566            }
5567            po.push("</tr>");
5568            i++;
5569        }
5570        po.push("</tbody>");
5571        po.push("</table>");
5572        po.push("</div>");
5573        axdom("#" + cfg.targetID).html(po.join(''));
5574    },
5575    /**
5576     * @method AXCalendar.yearPageSetYear
5577     * @param {Date} - 날짜
5578     * @returns {AXCalendar}
5579     * @description 년도달력의 표시 날짜를 변경합니다.
5580     * @example
5581     *```js
5582     * var myDate = new Date();
5583     * // var myDate = "2014-11-01".date();
5584     * mycalendar.yearPageSetYear(myDate);
5585     *```
5586     */
5587    yearPageSetYear: function (date) {
5588        var cfg = this.config;
5589        axdom("#" + cfg.targetID).find(".calendarMonth").removeClass("selected");
5590        axdom("#" + cfg.targetID + "_AX_" + date.print("yyyy") + "_AX_year").addClass("selected");
5591    },
5592    /**
5593     * @method AXCalendar.printTimePage
5594     * @param {String}
5595     * @returns {AXCalendar}
5596     * @description 시간 선택 캘린더를 targetID 안에 출력합니다.
5597     * @example
5598     *```js
5599     * mycalendar.printTimePage("06:36 AM");
5600     *```
5601     */
5602    printTimePage: function (displayTime) {
5603        var cfg = this.config;
5604        if (Object.isUndefined(cfg.targetID)) {
5605            trace("need targetID - setConfig({targetID:''})");
5606            return;
5607        }
5608
5609        if (displayTime) {
5610            var now = displayTime.split(":");
5611            var hh = now[0].setDigit(2);
5612            var mm = now[1].left(2).setDigit(2);
5613            var apm = now[1].right(2);
5614            if (hh == "00" && mm == "00") {
5615                //hh = "12";
5616                apm = "AM";
5617            }
5618            if (apm == "00") apm = "AM";
5619        } else {
5620            var now = new Date();
5621            var hh = now.getHours();
5622            var mm = now.getMinutes();
5623            var apm = "AM";
5624            if (hh == 0 && mm == 0) {
5625                //hh = 24;
5626            }
5627            if (hh > 12) {
5628                apm = "PM";
5629                hh -= 12;
5630            }
5631            hh = hh.setDigit(2);
5632            mm = mm.setDigit(2);
5633        }
5634
5635        var po = [];
5636        po.push("<div id=\"" + cfg.targetID + "_AX_box\" class=\"" + cfg.CT_className + "\" style=\"padding:0px;\">");
5637        po.push("<div class='timeBox'>");
5638        po.push("<div class='hourTitle'>Hour</div>");
5639        po.push("<div class='hourSlider'><input type='text' value='" + hh + "' id='" + cfg.targetID + "_AX_hour' class='AXInput' /></div>");
5640        po.push("<div class='minuteTitle'>Minute</div>");
5641        po.push("<div class='minuteSlider'><input type='text' value='" + mm + "' id='" + cfg.targetID + "_AX_minute' class='AXInput' /></div>");
5642        po.push("<div class='timeDisplay'>
5642" + hh + ":" + mm + " " + apm + "</div>");
5643        po.push("<div class='AMPM'><input type='text' id='" + cfg.targetID + "_AX_AMPM' value='" + apm + "' style='width:50px;height:21px;border:0px none;' /></div>");
5644        po.push("</div>");
5645        po.push("</div>");
5646        axdom("#" + cfg.targetID).html(po.join(''));
5647
5648        var timePageChange = this.timePageChange.bind(this);
5649        axdom("#" + cfg.targetID + "_AX_hour").unbindInput();
5650        axdom("#" + cfg.targetID + "_AX_minute").unbindInput();
5651        axdom("#" + cfg.targetID + "_AX_AMPM").unbindInput();
5652        axdom("#" + cfg.targetID + "_AX_hour").bindSlider({
5653            min: 0, max: 12, onChange: function (objID, objVal) {
5654                timePageChange(objID, objVal);
5655            }
5656        });
5657        axdom("#" + cfg.targetID + "_AX_minute").bindSlider({
5658            min: 0, max: 59, onChange: function (objID, objVal) {
5659                timePageChange(objID, objVal);
5660            }
5661        });
5662        axdom("#" + cfg.targetID + "_AX_AMPM").bindSwitch({
5663            off: "AM", on: "PM", onChange: function (objID, objVal) {
5664                timePageChange(objID, objVal);
5665            }
5666        });
5667    },
5668	// 내부 함수
5669    timePageChange: function () {
5670        var cfg = this.config, hh, mi, apm, mytime;
5671	    hh = axdom("#" + cfg.targetID + "_AX_hour").val().number();
5672	    mi = axdom("#" + cfg.targetID + "_AX_minute").val().number();
5673	    apm = axdom("#" + cfg.targetID + "_AX_AMPM").val();
5674        if(apm == "PM"){
5675	        //hh += 12;
5676            if(hh > 12){
5677                axdom("#" + cfg.targetID + "_AX_hour").val(12);
5678                axdom("#" + cfg.targetID + "_AX_hour").setValueInput(12);
5679            }
5680        }
5681        mytime = hh.setDigit(2) + ":" + mi.setDigit(2) + " " + apm;
5682        axdom("#" + cfg.targetID + "_AX_box").find(".timeDisplay").html(mytime);
5683        if (cfg.onChange) {
5684            cfg.onChange(hh.setDigit(2) + ":" + mi.setDigit(2));
5685        }
5686    },
5687    /**
5688     * @method AXCalendar.getTime
5689     * @returns {String} hh:mm
5690     * @description 현재 시간과 분을 리턴합니다.
5691     * @example
5692     *```js
5693     * myCalendar.getTime();
5694     * // 09:20
5695     *```
5696     */
5697    getTime: function () {
5698        var cfg = this.config;
5699        var hh = (axdom("#" + cfg.targetID + "_AX_hour").val()||0).number();
5700        var mi = (axdom("#" + cfg.targetID + "_AX_minute").val()||0).number();
5701        var apm = axdom("#" + cfg.targetID + "_AX_AMPM").val();
5702        if (apm == "PM" && hh < 12) hh += 12;
5703        return hh.setDigit(2) + ":" + mi.setDigit(2);
5704    }
5705});
5706/* ---------------------------------------------- AXCalendar -- */
5707
5708/* -- AXMultiSelect ---------------------------------------------- */
5709/**
5710 * @class AXMultiSelect
5711 * @classdesc 박스안에 아이템들중에 약속된 Class를 가진 아이템에 대해 다중선택를 할 수 있도록 지원합니다.
5712 * @extends AXJ
5713 * @version v1.9
5714 * @author [email protected]
5715 * @logs
5716 "2013-01-31 오후 5:01:12",
5717 "2013-11-12 오전 9:19:09 - tom : 버그픽스",
5718 "2013-11-12 오전 11:59:38 - tom : body relative 버그 픽스, 스크롤바 마우스 선택 문제 해결",
5719 "2013-11-13 오후 3:01:15 - tom : 모바일 터치 기능 지원"
5720 "2015-04-01 tom : 드래그 셀렉트 버그 픽스"
5721 * @example
5722 *```js
5723 * var multiSelector = new AXMultiSelect();
5724 * multiSelector.setConfig({
5725 *     selectStage       : "selectStageBox", // 컨테이너 타겟 아이디
5726 *     selectClassName   : "readyselect", // 셀렉트 대상
5727 *     beselectClassName : "beSelected", // 셀렉트 되었을 때.
5728 *     selectingClassName: "AX_selecting" // 셀렉트중일 때
5729 * });
5730 *```
5731 */
5732var AXMultiSelect = Class.create(AXJ, {
5733    initialize: function (AXJ_super) {
5734        AXJ_super();
5735
5736        /**
5737         * 선택된 아이템 <en>Array of selected Item.</en>
5738         * @member {Array} AXMultiSelect.selects
5739         */
5740        this.selects = [];
5741	    this.moveSens = 0;
5742	    this.touchMode;
5743
5744        this.config.selectClassName = "readySelect";
5745        this.config.beselectClassName = "beSelected";
5746        this.config.selectingClassName = "AX_selecting";
5747        this.config.moveSens = 5;
5748        this.config.useHelper = true;
5749    },
5750    /**
5751     * @method AXMultiSelect.setConfig
5752     * @param {Object} config
5753     * @description 멀티셀렉트
5754     * @example
5755     *```js
5756     * var config = {
5757     *     selectStage: {String} - Element ID of select item container,
5758     *     selectClassName: {String} [readySelect] - CSS Class Name of select item,
5759     *     beselectClassName: {String} [beSelected] - CSS Class Name of selected item,
5760     *     selectingClassName: {String} [AX_selecting] - CSS Class Name of selecting item,
5761     *     moveSens: {Number} [5] - mouse position move of detect select,
5762     *     useHelper: {Boolean} [true] - use mouse select box
5763     * }
5764     * multiSelector.setConfig(config);
5765     *```
5766     */
5767    init: function () {
5768
5769        var mouseClick = this.onmouseClick.bind(this);
5770        this._selectStage = axdom("#" + this.config.selectStage);
5771        this._selectStage.css({ "position": "relative" });
5772
5773        /*
5774         if(AXUtil.browser.mobile){
5775         this._selectStage.css({"overflow":"visible", "min-height":this._selectStage.innerHeight(), "height":"auto"});
5776         }
5777         */
5778
5779        this._selectStage.bind("mousedown", this.mousedown.bind(this));
5780
5781        this._selectStage.bind("click", function (event) {
5782            mouseClick(this, event);
5783        });
5784
5785        this.helper = axdom("<div class='AXMultiselectorHelper'></div>");
5786        this.collect();
5787
5788        axdom(window).bind("resize.AXMultiSelect", this.collect.bind(this));
5789        axdom(window).bind("keydown.AXMultiSelect", this.onKeydown.bind(this));
5790        this._selectStage.bind("scroll", this.onScrollStage.bind(this));
5791
5792        this._selectStage.bind("touchstart", this.touchstart.bind(this));
5793    },
5794    onKeydown: function (event) {
5795        if (event.keyCode == AXUtil.Event.KEY_ESC) {
5796            this.clearSelects();
5797        }
5798    },
5799    onScrollStage: function (event) {
5800        var cfg = this.config;
5801        if (!AXUtil.browser.mobile) {
5802            if (this.helperAppened || this.helperAppenedReady) {
5803                this.moveSens = 0;
5804                axdom(document.body).unbind("mousemove.AXMultiSelect");
5805                axdom(document.body).unbind("mouseup.AXMultiSelect");
5806                axdom(document.body).unbind("mouseleave.AXMultiSelect");
5807                axdom(document.body).removeAttr("onselectstart");
5808                //axdom(document.body).removeClass("AXUserSelectNone");
5809                this.helperAppenedReady = false;
5810                this.helperAppened = false;
5811                this.helper.remove();
5812            }
5813        }
5814
5815    },
5816    /* ------------------------------------------------------------------------------------------------------------------ */
5817    /* observe method ~~~~~~ */
5818    onmouseClick: function (element, event) {
5819        if (this.helperAppened){
5820            return this;
5821        }
5822        var cfg = this.config;
5823        var eid = event.target.id.split(/_AX_/g);
5824        var eventTarget = event.target;
5825        var myTarget = this.getEventTarget({
5826            evt: eventTarget, evtIDs: eid,
5827            until: function (evt, evtIDs) { return (AXgetId(evt.parentNode) == AXgetId(cfg.selectStage)) ? true : false; },
5828            find: function (evt, evtIDs) { return (axdom(evt).hasClass(cfg.selectClassName)) ? true : false; }
5829        });
5830
5831        if (myTarget) {
5832            var selectElement = myTarget;
5833            if (selectElement) {
5834                if (event.shiftKey) {
5835                    this.shiftSelects(selectElement);
5836                } else if (event.metaKey || event.ctrlKey) {
5837                    this.toggleSelects(selectElement);
5838                } else {
5839                    this.clickSelects(selectElement);
5840                }
5841            }
5842        } else {
5843            if (event.target.id == cfg.selectStage && AXUtil.browser.name != "ie") this.clearSelects();
5844        }
5845        return this;
5846    },
5847    /* ------------------------------------------------------------------------------------------------------------------ */
5848    /* class method ~~~~~~ */
5849    /**
5850     * @method AXMultiSelect.collect
5851     * @returns {AXMultiSelect}
5852     * @description 컨테이너안에 셀렉트 아이템을 재정의 합니다.
5853     * @example
5854     *```js
5855     * multiSelector.collect();
5856     * // 컨테이너안에 아이템의 변화가 생긴 경우 호출합니다.
5857     *```
5858     */
5859    collect: function () {
5860        var cfg = this.config;
5861        this._selectTargets = axdom("#" + cfg.selectStage + " ." + cfg.selectClassName);
5862        this.selectTargets = this._selectTargets.get();
5863        var scrollLeft = this._selectStage.scrollLeft().number();
5864        var scrollTop = this._selectStage.scrollTop().number();
5865        this._selectTargets.each(function () {
5866            var jQuerythis = axdom(this), pos = jQuerythis.position();
5867            axdom.data(this, "selectableItem", {
5868                element: this,
5869                jQueryelement: jQuerythis,
5870                left: pos.left + scrollLeft,
5871                top: pos.top + scrollTop,
5872                right: pos.left + scrollLeft + jQuerythis.outerWidth(),
5873                bottom: pos.top + scrollTop + jQuerythis.outerHeight(),
5874                selected: jQuerythis.hasClass(cfg.beselectClassName),
5875                selecting: jQuerythis.hasClass(cfg.selectingClassName)
5876            });
5877        });
5878	    return this;
5879    },
5880    clearSelects: function () {
5881        var cfg = this.config;
5882        this._selectTargets.each(function () {
5883            var selectTarget = axdom.data(this, "selectableItem");
5884            if (selectTarget) {
5885                if (selectTarget.selecting) {
5886                    selectTarget.jQueryelement.removeClass(cfg.selectingClassName);
5887                    selectTarget.selecting = false;
5888                }
5889                if (selectTarget.selected) {
5890                    selectTarget.jQueryelement.removeClass(cfg.beselectClassName);
5891                    selectTarget.selected = false;
5892                }
5893            }
5894        });
5895    },
5896    pushSelects: function (Obj) {
5897        var hasSelect = this.selects.has(function () {
5898            return this.item == Obj;
5899        });
5900        if (!hasSelect) this.selects.push(Obj);
5901    },
5902    clickSelects: function (Obj) {
5903        var cfg = this.config;
5904
5905        this.clearSelects();
5906
5907        var selectTarget = axdom.data(Obj, "selectableItem");
5908        selectTarget.jQueryelement.addClass(cfg.beselectClassName);
5909        selectTarget.selected = true;
5910    },
5911    toggleSelects: function (Obj) {
5912        var cfg = this.config;
5913
5914        var selectTarget = axdom.data(Obj, "selectableItem");
5915        if (selectTarget.selected) {
5916            selectTarget.jQueryelement.removeClass(cfg.beselectClassName);
5917            selectTarget.selected = false;
5918        } else {
5919            selectTarget.jQueryelement.addClass(cfg.beselectClassName);
5920            selectTarget.selected = true;
5921        }
5922    },
5923    shiftSelects: function (Obj) {
5924        var cfg = this.config;
5925
5926        var selectedLength = 0;
5927        var li, si;
5928        this._selectTargets.each(function (stIndex, ST) {
5929            var selectTarget = axdom.data(this, "selectableItem");
5930            if (selectTarget) {
5931                if (selectTarget.selected) {
5932                    selectedLength++;
5933                    li = stIndex;
5934                }
5935            }
5936            if (this === Obj) si = stIndex;
5937        });
5938
5939        if (selectedLength == 0) {
5940            this.clickSelects(Obj);
5941        } else {
5942            //마지막 selects 개체를 찾는다.
5943            if (si == li) return;
5944            this.clearSelects();
5945            var temp;
5946            if (si > li) {
5947                temp = si;
5948                si = li;
5949                li = temp;
5950            }
5951            this._selectTargets.each(function (stIndex, ST) {
5952                var selectTarget = axdom.data(this, "selectableItem");
5953                if (selectTarget) {
5954                    if (si <= stIndex && li >= stIndex) {
5955                        selectTarget.jQueryelement.addClass(cfg.beselectClassName);
5956                        selectTarget.selected = true;
5957                    }
5958                }
5959            });
5960        }
5961    },
5962
5963    /* mouser helper */
5964    mousedown: function (event) {
5965        var cfg = this.config;
5966
5967        axdom(document.body).bind("mousemove.AXMultiSelect", this.mousemove.bind(this));
5968        axdom(document.body).bind("mouseup.AXMultiSelect", this.mouseup.bind(this));
5969        axdom(document.body).bind("mouseleave.AXMultiSelect", this.mouseup.bind(this));
5970        axdom(document.body).attr("onselectstart", "return false");
5971        //axdom(document.body).addClass("AXUserSelectNone");
5972
5973        this.helperAppenedReady = true;
5974    },
5975    mousemove: function (event) {
5976        var cfg = this.config;
5977        if (!event.pageX) return;
5978
5979        /*드래그 감도 적용 */
5980        if (this.config.moveSens > this.moveSens) this.moveSens++;
5981        if (this.moveSens == this.config.moveSens) this.selectorHelperMove(event);
5982    },
5983    mouseup: function (event) {
5984        var cfg = this.config, _this = this;
5985
5986        this.helperAppenedReady = false;
5987        this.moveSens = 0;
5988
5989        axdom(document.body).unbind("mousemove.AXMultiSelect");
5990        axdom(document.body).unbind("mouseup.AXMultiSelect");
5991        axdom(document.body).unbind("mouseleave.AXMultiSelect");
5992
5993        axdom(document.body).removeAttr("onselectstart");
5994        //axdom(document.body).removeClass("AXUserSelectNone");
5995
5996        if (this.helperAppened) {
5997            setTimeout(function(){
5998                _this.helperAppened = false;
5999                _this.helper.remove();
6000            }, 100);
6001
6002
6003            /* selected change */
6004            this._selectTargets.each(function () {
6005                var selectTarget = axdom.data(this, "selectableItem");
6006                if (selectTarget) {
6007                    if (selectTarget.selecting) {
6008                        selectTarget.jQueryelement.removeClass(cfg.selectingClassName);
6009                        selectTarget.selecting = false;
6010                        selectTarget.jQueryelement.addClass(cfg.beselectClassName);
6011                        selectTarget.selected = true;
6012                    }
6013                    /*
6014                    else if (selectTarget.selected) {
6015
6016                    }
6017                    */
6018                }
6019            });
6020        }
6021
6022    },
6023    selectorHelperMove: function (event) {
6024        var cfg = this.config;
6025
6026        if (!cfg.useHelper) {
6027            return;
6028        }
6029
6030        if (this.helperAppened) {
6031
6032            var _helperPos = this.helperPos;
6033            var tmp,
6034                x1 = this.helperPos.x,
6035                y1 = this.helperPos.y,
6036                x2 = event.pageX - _helperPos.bodyLeft,
6037                y2 = event.pageY - _helperPos.bodyTop;
6038            if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
6039            if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
6040            this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
6041
6042            this._selectTargets.each(function () {
6043
6044                var selectTarget = axdom.data(this, "selectableItem"), hit = false;
6045                /*trace({sl:selectTarget.left, sr:selectTarget.right, st:selectTarget.top, sb:selectTarget.bottom, x1:x1, x2:x2, y1:y1, y2:y2}); */
6046                if (!selectTarget) return;
6047
6048                var stL = selectTarget.left.number(), stR = selectTarget.right.number(), stT = selectTarget.top.number(), stB = selectTarget.bottom.number();
6049                stL = stL + _helperPos.stageX - _helperPos.scrollLeft - _helperPos.bodyLeft;
6050                stR = stR + _helperPos.stageX - _helperPos.scrollLeft - _helperPos.bodyLeft;
6051                stT = stT + _helperPos.stageY - _helperPos.scrollTop - _helperPos.bodyTop;
6052                stB = stB + _helperPos.stageY - _helperPos.scrollTop - _helperPos.bodyTop;
6053
6054                hit = (!(stL > x2 || stR < x1 || stT > y2 || stB < y1)); /* touch */
6055                /* hit = (selectTarget.left > x1 && selectTarget.right < x2 && selectTarget.top > y1 && selectTarget.bottom < y2); fit */
6056                if (hit) {
6057                    /* SELECT */
6058                    if (selectTarget.selected) {
6059                        selectTarget.jQueryelement.removeClass(cfg.beselectClassName);
6060                        selectTarget.selected = false;
6061                    }
6062                    if (!selectTarget.selecting) {
6063                        selectTarget.jQueryelement.addClass(cfg.selectingClassName);
6064                        selectTarget.selecting = true;
6065                    }
6066                } else {
6067                    /* UNSELECT */
6068                    if (selectTarget.selecting) {
6069                        selectTarget.jQueryelement.removeClass(cfg.selectingClassName);
6070                        selectTarget.selecting = false;
6071                    }
6072                    if (selectTarget.selected) {
6073                        if (!event.metaKey && !event.shiftKey && !event.ctrlKey) {
6074                            selectTarget.jQueryelement.removeClass(cfg.beselectClassName);
6075                            selectTarget.selected = false;
6076                        }
6077                    }
6078                }
6079            });
6080
6081        } else {
6082            this.helperAppened = true;
6083            axdom(document.body).append(this.helper);
6084
6085            var css = { left: (event.pageX - axdom(document.body).offset().left), top: (event.pageY - axdom(document.body).offset().top), width: 0, height: 0 };
6086            this.helper.css(css);
6087            var stagePos = this._selectStage.offset();
6088            this.helperPos = {
6089                stageX: stagePos.left.number(),
6090                stageY: stagePos.top.number(),
6091                x: css.left.number(),
6092                y: css.top.number(),
6093                scrollLeft: this._selectStage.scrollLeft().number(),
6094                scrollTop: this._selectStage.scrollTop().number(),
6095                bodyLeft: axdom(document.body).offset().left,
6096                bodyTop: axdom(document.body).offset().top
6097            };
6098        }
6099    },
6100
6101    /* touch helper */
6102    touchstart: function (event) {
6103        var cfg = this.config;
6104
6105        var touchEnd = this.touchEnd.bind(this);
6106        this.touchEndBind = function () {
6107            touchEnd(event);
6108        };
6109
6110        var touchMove = this.touchMove.bind(this);
6111        this.touchMoveBind = function () {
6112            touchMove(event);
6113        };
6114
6115        if (document.addEventListener) {
6116            document.addEventListener("touchend", this.touchEndBind, false);
6117            document.addEventListener("touchmove", this.touchMoveBind, false);
6118        }
6119
6120        this.helperAppenedReady = true;
6121    },
6122    touchMove: function (event) {
6123        var cfg = this.config;
6124        var event = window.event || e;
6125        var touch = event.touches[0];
6126        if (!touch.pageX) return;
6127        var offset = this._selectStage.offset();
6128        var right = offset.left + this._selectStage.width();
6129        var bottom = offset.top + this._selectStage.height();
6130
6131        if (this.moveSens == 0) {
6132            this.touchStartXY = { x: touch.pageX, y: touch.pageY, scrollTop: this._selectStage.scrollTop() };
6133        }
6134
6135        /*드래그 감도 적용 */
6136        if (this.config.moveSens > this.moveSens) this.moveSens++;
6137        if (this.moveSens == this.config.moveSens) {
6138            if (this.touchMode == "drag") {
6139                if (bottom < touch.pageY) this._selectStage.scrollTop(this.touchStartXY.scrollTop - (bottom - touch.pageY));
6140                else if (offset.top > touch.pageY) this._selectStage.scrollTop(this.touchStartXY.scrollTop - (offset.top - touch.pageY));
6141                if (right < touch.pageX) this._selectStage.scrollLeft(this.touchStartXY.scrollLeft - (right - touch.pageX));
6142                else if (offset.left > touch.pageX) this._selectStage.scrollLeft(this.touchStartXY.scrollLeft - (offset.left - touch.pageX));
6143                this.selectorHelperMoveByTouch(event);
6144            } else if (this.touchMode == "scrollTop") {
6145                this._selectStage.scrollTop(this.touchStartXY.scrollTop + (this.touchStartXY.y - touch.pageY));
6146            } else if (this.touchMode == "scrollLeft") {
6147                this._selectStage.scrollLeft(this.touchStartXY.scrollLeft + (this.touchStartXY.x - touch.pageX));
6148            } else {
6149                if (((this.touchStartXY.x - touch.pageX).abs() - (this.touchStartXY.y - touch.pageY).abs()).abs() < 5) {
6150                    this.touchMode = "drag"
6151                    this.selectorHelperMoveByTouch(event);
6152                } else if ((this.touchStartXY.x - touch.pageX).abs() < (this.touchStartXY.y - touch.pageY).abs()) {
6153                    this.touchMode = "scrollTop";
6154                    this._selectStage.scrollTop(this.touchStartXY.scrollTop + (this.touchStartXY.y - touch.pageY));
6155                } else if ((this.touchStartXY.x - touch.pageX).abs() > (this.touchStartXY.y - touch.pageY).abs()) {
6156                    this.touchMode = "scrollLeft";
6157                    this._selectStage.scrollLeft(this.touchStartXY.scrollLeft + (this.touchStartXY.x - touch.pageX));
6158                }
6159            }
6160        }
6161
6162        if (event.preventDefault) event.preventDefault();
6163        else return false;
6164    },
6165    selectorHelperMoveByTouch: function (e) {
6166        var cfg = this.config;
6167        var event = window.event || e;
6168        var touch = event.touches[0];
6169
6170        if (this.helperAppened) {
6171
6172            var _helperPos = this.helperPos;
6173            var tmp,
6174                x1 = this.helperPos.x,
6175                y1 = this.helperPos.y,
6176                x2 = touch.pageX - _helperPos.bodyLeft,
6177                y2 = touch.pageY - _helperPos.bodyTop;
6178            if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
6179            if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
6180            this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
6181
6182            this._selectTargets.each(function () {
6183
6184                var selectTarget = axdom.data(this, "selectableItem"), hit = false;
6185                /*trace({sl:selectTarget.left, sr:selectTarget.right, st:selectTarget.top, sb:selectTarget.bottom, x1:x1, x2:x2, y1:y1, y2:y2}); */
6186                if (!selectTarget) return;
6187
6188                var stL = selectTarget.left.number(), stR = selectTarget.right.number(), stT = selectTarget.top.number(), stB = selectTarget.bottom.number();
6189                stL = stL + _helperPos.stageX - _helperPos.scrollLeft - _helperPos.bodyLeft;
6190                stR = stR + _helperPos.stageX - _helperPos.scrollLeft - _helperPos.bodyLeft;
6191                stT = stT + _helperPos.stageY - _helperPos.scrollTop - _helperPos.bodyTop;
6192                stB = stB + _helperPos.stageY - _helperPos.scrollTop - _helperPos.bodyTop;
6193
6194                hit = (!(stL > x2 || stR < x1 || stT > y2 || stB < y1)); /* touch */
6195                /* hit = (selectTarget.left > x1 && selectTarget.right < x2 && selectTarget.top > y1 && selectTarget.bottom < y2); fit */
6196                if (hit) {
6197                    /* SELECT */
6198                    if (selectTarget.selected) {
6199                        selectTarget.jQueryelement.removeClass(cfg.beselectClassName);
6200                        selectTarget.selected = false;
6201                    }
6202                    if (!selectTarget.selecting) {
6203                        selectTarget.jQueryelement.addClass(cfg.selectingClassName);
6204                        selectTarget.selecting = true;
6205                    }
6206                } else {
6207                    /* UNSELECT */
6208                    if (selectTarget.selecting) {
6209                        selectTarget.jQueryelement.removeClass(cfg.selectingClassName);
6210                        selectTarget.selecting = false;
6211                    }
6212                    if (selectTarget.selected) {
6213                        if (!event.metaKey && !event.shiftKey && !event.ctrlKey) {
6214                            selectTarget.jQueryelement.removeClass(cfg.beselectClassName);
6215                            selectTarget.selected = false;
6216                        }
6217                    }
6218                }
6219            });
6220
6221        } else {
6222            this.helperAppened = true;
6223            axdom(document.body).append(this.helper);
6224
6225            var css = { left: (touch.pageX - axdom(document.body).offset().left), top: (touch.pageY - axdom(document.body).offset().top), width: 0, height: 0 };
6226            this.helper.css(css);
6227            var stagePos = this._selectStage.offset();
6228            this.helperPos = {
6229                stageX: stagePos.left.number(),
6230                stageY: stagePos.top.number(),
6231                x: css.left.number(),
6232                y: css.top.number(),
6233                scrollLeft: this._selectStage.scrollLeft().number(),
6234                scrollTop: this._selectStage.scrollTop().number(),
6235                bodyLeft: axdom(document.body).offset().left,
6236                bodyTop: axdom(document.body).offset().top
6237            };
6238        }
6239    },
6240    touchEnd: function (e) {
6241        var cfg = this.config;
6242        var event = window.event || e;
6243        this.helperAppenedReady = false;
6244        this.moveSens = 0;
6245
6246        this.touchMode = false;
6247
6248        if (document.removeEventListener) {
6249            document.removeEventListener("touchend", this.touchEndBind, false);
6250            document.removeEventListener("touchmove", this.touchMoveBind, false);
6251        }
6252
6253        if (this.helperAppened) {
6254            this.helperAppened = false;
6255            this.helper.remove();
6256
6257            /* selected change */
6258            this._selectTargets.each(function () {
6259                var selectTarget = axdom.data(this, "selectableItem");
6260                if (selectTarget) {
6261                    if (selectTarget.selecting) {
6262                        selectTarget.jQueryelement.removeClass(cfg.selectingClassName);
6263                        selectTarget.selecting = false;
6264                        selectTarget.jQueryelement.addClass(cfg.beselectClassName);
6265                        selectTarget.selected = true;
6266                    } else if (selectTarget.selected) {
6267
6268                    }
6269                }
6270            });
6271        }
6272    },
6273    /**
6274     * @method AXMultiSelect.getSelects
6275     * @returns {Array} selects
6276     * @description 셀렉트된 아이템 엘리먼트 배열을 반환합니다. Return Array of selected item element
6277     * @example
6278     *```js
6279     * multiSelector.getSelects();
6280     *```
6281     */
6282    getSelects: function () {
6283        var cfg = this.config;
6284        var selects = [];
6285        this._selectTargets.each(function () {
6286            var selectTarget = axdom.data(this, "selectableItem");
6287            if (selectTarget) {
6288                if (selectTarget.selected) {
6289                    selects.push(selectTarget.element);
6290                }
6291            }
6292        });
6293        return selects;
6294    },
6295    size: function () {
6296        var cfg = this.config;
6297        var selects = [];
6298        this._selectTargets.each(function () {
6299            var selectTarget = axdom.data(this, "selectableItem");
6300            if (selectTarget) {
6301                if (selectTarget.selected) {
6302                    selects.push(selectTarget.element);
6303                }
6304            }
6305        });
6306        return selects.length;
6307    }
6308});
6309/* ---------------------------------------------- AXMultiSelect -- */
6310
6311/* -- AXResizable ---------------------------------------------- */
6312/**
6313 * 아이템을 주어진 조건에 맞게 리사이즈 할 수 있는 클래스
6314 * @class AXResizable
6315 * @classdesc
6316 * @extends AXJ
6317 * @version v0.9
6318 * @author [email protected]
6319 * @logs
6320 "2013-11-12 오전 10:22:06"
6321 */
6322var AXResizable = Class.create(AXJ, {
6323    initialize: function (AXJ_super) {
6324        AXJ_super();
6325        this.moveSens = 0;
6326	    this.objects = [];
6327
6328        this.config.moveSens = 2;
6329        this.config.bindResiableContainer = "AXResizable";
6330        this.config.bindResiableHandle = "AXResizableHandle";
6331    },
6332/**
6333 * @method AXResizable.setConfig
6334 * @param {Object} config
6335 * @description targetID를 지정합니다. 인스턴스간에 구분을 할 수 있게 해줍니다.
6336 * @example
6337```js
6338 var AXResizableBinder = new AXResizable();
6339 AXResizableBinder.setConfig({ targetID: "defaultResiable" });
6340```
6341 */
6342    init: function () {
6343        this.helper = axdom("<div class='AXResizableHelper'></div>");
6344    },
6345/**
6346 * @method AXResizable.bind
6347 * @param {Object} obj
6348 * @returns {AXResizable}
6349 * @example
6350```js
6351 var config = {
6352    id: {String} - Element ID,
6353    minWidth: {Number} [0],
6354    minHeight: {Number} [0],
6355	maxWidth: {Number} [0],
6356	maxHeight: {Number} [0],
6357	animate: {easing:"bounceOut", duration:500},
6358	aspectRatio: {Number} - 2/1,
6359	snap: {Number} - 10,
6360	onChange: function(){
6361		// this.id, this.element, this.jQueryElement, this.config
6362		toast.push(this.id);
6363	}
6364 };
6365 myResizer.bind(config);
6366```
6367 */
6368    bind: function (obj) {
6369        var cfg = this.config;
6370        if (!obj.id) {
6371            trace("bind 대상 ID가 없어 bind 처리할 수 없습니다.");
6372            return;
6373        }
6374        if (!AXgetId(obj.id)) {
6375            trace("bind 대상이 없어 bind 처리할 수 없습니다.");
6376            return;
6377        }
6378        var objID = obj.id;
6379        var objSeq = null;
6380
6381        AXUtil.each(this.objects, function (idx, O) {
6382            /*if (this.id == objID && this.isDel == true) objSeq = idx;*/
6383            if (this.id == objID) {
6384                objSeq = idx;
6385            }
6386        });
6387        if (objSeq == null) {
6388            objSeq = this.objects.length;
6389            this.objects.push({
6390                id: objID,
6391                element: AXgetId(objID),
6392                jQueryElement: axdom("#" + objID),
6393                config: obj
6394            });
6395        } else {
6396            this.objects[objSeq].isDel = undefined;
6397            this.objects[objSeq].config = obj;
6398        }
6399        this.bindResizer(objID, objSeq);
6400		return this;
6401    },
6402/**
6403 * @method AXResizable.unbind
6404 * @param {Object} obj
6405 * @returns {AXResizable}
6406 * @description 바인드 해제 합니다.
6407 * @example
6408```js
6409 myResizer.unbind({id:"ElementID"});
6410```
6411 */
6412    unbind: function (obj) {
6413        var cfg = this.config;
6414        var removeIdx;
6415        AXUtil.each(this.objects, function (idx, O) {
6416            if (O.id != obj.id) {
6417            } else {
6418                if (O.isDel != true) {
6419                    removeIdx = idx;
6420                }
6421            }
6422        });
6423        if (removeIdx != undefined) {
6424            this.objects[removeIdx].isDel = true;
6425            /* unbind 구문 */
6426        }
6427		return this;
6428    },
6429    bindResizer: function (objID, objSeq) {
6430        var _this = this;
6431        var cfg = this.config;
6432
6433        var obj = this.objects[objSeq];
6434
6435        var po = [];
6436        po.push("<div class=\"" + cfg.bindResiableHandle + "\"></div>");
6437        obj.jQueryElement.addClass(cfg.bindResiableContainer);
6438        obj.jQueryElement.append(po.join(''));
6439
6440        //obj.jQueryElement.bind("mousedown.AXResizable", function(){_this.mousedown(objID, objSeq, event)});
6441        obj.jQueryElement.bind("mousedown.AXResizable", this.mousedown.bind(this, obj
6441ID, objSeq));
6442    },
6443    mousedown: function (objID, objSeq, event) {
6444        var _this = this;
6445        var cfg = this.config;
6446
6447        axdom(window).bind("mousemove.AXResizable", this.mousemove.bind(this, objID, objSeq));
6448        axdom(window).bind("mouseup.AXResizable", this.mouseup.bind(this, objID, objSeq));
6449        /*axdom(document.body).bind("mouseleave.AXResizable", this.mouseup.bind(this, objID, objSeq));*/
6450
6451        axdom(document.body).attr("onselectstart", "return false");
6452        //axdom(document.body).addClass("AXUserSelectNone");
6453
6454        this.helperAppenedReady = true;
6455    },
6456    mousemove: function (objID, objSeq, event) {
6457        var cfg = this.config;
6458        if (!event.pageX) return;
6459
6460        /*드래그 감도 적용 */
6461        if (this.config.moveSens > this.moveSens) this.moveSens++;
6462        if (this.moveSens == this.config.moveSens) this.selectorHelperMove(objID, objSeq, event);
6463    },
6464    mouseup: function (objID, objSeq, event) {
6465        var cfg = this.config;
6466        var obj = this.objects[objSeq];
6467
6468        this.helperAppenedReady = false;
6469        this.moveSens = 0;
6470
6471        axdom(window).unbind("mousemove.AXResizable");
6472        axdom(window).unbind("mouseup.AXResizable");
6473        /*axdom(document.body).unbind("mouseleave.AXResizable");*/
6474
6475        axdom(document.body).removeAttr("onselectstart");
6476        //axdom(document.body).removeClass("AXUserSelectNone");
6477
6478        if (this.helperAppened) {
6479            this.helperAppened = false;
6480
6481            var newWidth = this.helper.width();
6482            var newHeight = this.helper.height();
6483
6484            var paddingLeft = obj.jQueryElement.css("padding-left");
6485            var paddingRight = obj.jQueryElement.css("padding-right");
6486            var paddingTop = obj.jQueryElement.css("padding-top");
6487            var paddingBottom = obj.jQueryElement.css("padding-bottom");
6488            var paddingW = paddingLeft.number() + paddingRight.number();
6489            var paddingH = paddingTop.number() + paddingBottom.number();
6490
6491            if (obj.config.animate) {
6492                obj.jQueryElement.animate(
6493                    { width: newWidth - paddingW, height: newHeight - paddingH },
6494                    (obj.config.animate.duration || 300), (obj.config.animate.easing || "liner"),
6495                    function () {
6496                        if (obj.config.onChange) {
6497                            obj.config.onChange.call(obj, obj);
6498                        }
6499                    }
6500                );
6501            } else {
6502                obj.jQueryElement.css({ width: newWidth - paddingW, height: newHeight - paddingH });
6503                if (obj.config.onChange) {
6504                    obj.config.onChange.call(obj, obj);
6505                }
6506            }
6507
6508            this.helper.remove();
6509        }
6510    },
6511    selectorHelperMove: function (objID, objSeq, event) {
6512        var cfg = this.config;
6513        var obj = this.objects[objSeq];
6514
6515        if (this.helperAppened) {
6516
6517            var _helperPos = this.helperPos;
6518            var tmp,
6519                x1 = this.helperPos.x,
6520                y1 = this.helperPos.y,
6521                x2 = event.pageX - _helperPos.bodyLeft,
6522                y2 = event.pageY - _helperPos.bodyTop;
6523
6524            var minWidth = (obj.config.minWidth || 0),
6525                minHeight = (obj.config.minHeight || 0),
6526                maxWidth = (obj.config.maxWidth || 0),
6527                maxHeight = (obj.config.maxHeight || 0);
6528
6529            var myWidth = x2 - x1, myHeight = y2 - y1;
6530
6531            if (minWidth != 0 && myWidth < minWidth) myWidth = minWidth;
6532            if (minHeight != 0 && myHeight < minHeight) myHeight = minHeight;
6533            if (maxWidth != 0 && myWidth > maxWidth) myWidth = maxWidth;
6534            if (maxHeight != 0 && myHeight > maxHeight) myHeight = maxHeight;
6535
6536            if (obj.config.aspectRatio) {
6537                myWidth = myHeight * obj.config.aspectRatio;
6538            }
6539
6540            if (obj.config.snap) {
6541                myWidth = obj.config.snap * (myWidth / obj.config.snap).ceil();
6542                myHeight = obj.config.snap * (myHeight / obj.config.snap).ceil();
6543            }
6544            //trace({width: myWidth, height: myHeight});
6545            this.helper.css({ width: myWidth, height: myHeight });
6546
6547        } else {
6548            this.helperAppened = true;
6549            axdom(document.body).append(this.helper);
6550
6551            var bodyLeft = axdom(document.body).offset().left;
6552            var bodyTop = axdom(document.body).offset().top;
6553
6554            var pos = obj.jQueryElement.offset();
6555            var css = {
6556                left: pos.left + bodyLeft,
6557                top: pos.top + bodyLeft,
6558                width: obj.jQueryElement.outerWidth(),
6559                height: obj.jQueryElement.outerHeight()
6560            };
6561            this.helper.css(css);
6562
6563            this.helperPos = {
6564                x: css.left,
6565                y: css.top,
6566                bodyLeft: axdom(document.body).offset().left,
6567                bodyTop: axdom(document.body).offset().top
6568            };
6569        }
6570    }
6571});
6572var AXResizableBinder = new AXResizable();
6573AXResizableBinder.setConfig({ targetID: "defaultResizable" });
6574
6575/**
6576 * @method jQueryExtends.bindAXResizable
6577 * @param {Object} config
6578 * @returns {jQueryObject}
6579 * @description box 엘리먼트 크기를 조정할 수 있게 해줍니다.
6580 * @example
6581 ```js
6582 $("#mytarget").bindAXResizable({
6583	minWidth:50, minHeight:50,
6584	maxWidth:200, maxHeight:200,
6585	animate: {easing:"bounceOut", duration:500},
6586	aspectRatio: 2/1,
6587	snap:10,
6588	onChange: function(){
6589		toast.push(this.id);
6590	}
6591 });
6592
6593 // 옵션 스펙
6594 var config = {
6595    minWidth: {Number} [0],
6596    minHeight: {Number} [0],
6597	maxWidth: {Number} [0],
6598	maxHeight: {Number} [0],
6599	animate: {easing:"bounceOut", duration:500},
6600	aspectRatio: {Number} - 2/1,
6601	snap: {Number} - 10,
6602	onChange: function(){
6603		// this.id, this.element, this.jQueryElement, this.config
6604		toast.push(this.id);
6605	}
6606 };
6607
6608 ```
6609 */
6610axdom.fn.bindAXResizable = function (config) {
6611    AXUtil.each(this, function () {
6612        config = config || {}; config.id = this.id;
6613        AXResizableBinder.bind(config);
6614        return this;
6615    });
6616	return this;
6617};
6618
6619/**
6620 * @method jQueryExtends.unbindAXResizable
6621 * @param {Object} [config]
6622 * @returns {jQueryObject}
6623 * @description box 엘리먼트 크기를 조정자를 제거합니다.
6624 * @example
6625 ```js
6626 $("#mytarget").unbindAXResizable();
6627 ```
6628 */
6629axdom.fn.unbindAXResizable = function (config) {
6630    AXUtil.each(this, function () {
6631        if (config == undefined) config = {};
6632        config.id = this.id;
6633        AXResizableBinder.unbind(config);
6634        return this;
6635    });
6636	return this;
6637};
6638/* ---------------------------------------------- AXResizable -- */
6639
6640/* -- AXContextMenu ---------------------------------------------- */
6641/**
6642 * AXContextMenuClass
6643 * @class AXContextMenuClass
6644 * @extends AXJ
6645 * @version v1.28
6646 * @author [email protected], axisj.com
6647 * @logs
6648 "2013-03-22 오후 6:08:57",
6649 "2013-09-03 오후 7:10:14 메뉴확장 위치 제어 버그 픽스",
6650 "2013-12-16 href=javascript 설정했을 때 onbeforeunload 이벤트 충돌문제 해결",
6651 "2013-12-26 오후 4:27:00 tom, left, top position ",
6652 "2014-02-11 오전 11:06:13 root, subMenu underLine, upperLine add",
6653 "2014-04-07 오전 9:55:57 tom, extent checkbox, sortbox"
6654 "2014-06-24 tom : reserveKeys.subMenu 설정할 수 있도록 기능 보강, 콜백함수 개선"
6655 "2014-12-18 tom : onclose 속성을 추가 할 수 있도록 속성 추가
6656 "2014-12-22 tom : filter를 통과한 메뉴 아이템이 없을 경우 표시 안하도록 변경"
6657 "2015-01-22 tom : item false 이면 표시 안하도록 변경"
6658 "2015-02-26 tom : bind를 다시 할때 reserveKeys 초기화 버그 픽스"
6659 */
6660
6661var AXContextMenuClass = Class.create(AXJ, {
6662    initialize: function (AXJ_super) {
6663        AXJ_super();
6664        this.showedItem = {};
6665        this.objects = [];
6666        this.config.theme = "AXContextMenu";
6667        this.config.width = "140";
6668        this.config.responsiveMobile = 0; /* 모바일 반응 너비 */
6669	    this.config.reserveKeys = {
6670		    subMenu: "subMenu"
6671	    };
6672    },
6673/**
6674 * @method AXContextMenuClass.setConfig
6675 * @param {Object} configs
6676 * @description 선언된 클래스를 사용하기 위해 속성을 정의합니다.
6677 * @example
6678```js
6679 var AXContextMenu = new AXContextMenuClass();
6680 AXContextMenu.setConfig({});
6681```
6682 */
6683    init: function () {
6684
6685    },
6686/**
6687 * @method AXContextMenuClass.bindSetConfig
6688 * @param {String} objID - object ID
6689 * @param {Object} configs - contentMenu config
6690 * @description contextmenu 오브젝트에 속성을 변경합니다.
6691 * @example
6692```js
6693 AXContextMenu.bindSetConfig("contenxt01", {});
6694```
6695 */
6696    bindSetConfig: function (objID, configs) {
6697        var findIndex = null;
6698        AXUtil.each(this.objects, function (index, O) {
6699            if (O.id == objID) {
6700                findIndex = index;
6701                return false;
6702            }
6703        });
6704        if (findIndex == null) {
6705            //trace("바인드 된 오브젝트를 찾을 수 없습니다.");
6706            return;
6707        } else {
6708            var _self = this.objects[findIndex];
6709            axf.each(configs, function (k, v) {
6710                _self.config[k] = v;
6711            });
6712        }
6713    },
6714/**
6715 * @method AXContextMenuClass.bind
6716 * @param {Object} obj - 컨텍스트메뉴 속성
6717 * @returns {AXContextMenuClass}
6718 * @description 컨텍스트메뉴를 선언하여 컨텍스트메뉴를 사용준비합니다. bind한 컨텍스트메뉴는 id로 open 할 수 있습니다.
6719 * @example
6720```js
6721 AXContextMenu.bind({
6722		id:"myContextMenu",
6723		theme:"AXContextMenu", // 선택항목
6724		width:"150", // 선택항목
6725		checkbox:"checkbox", // [checkbox|radio]
6726		sortbox:true,
6727		menu:[
6728			{
6729				label:'선택 1',
6730				checked:true,
6731				className: 'doc | docline | plus | minus | group | edit | copy | cut | paste | up | down | left | right | link | unlink | openall | closeall'
6732				onclick:function(){
6733					return false;
6734				}
6735			},
6736			{label:'선택 2', checked:true,
6737				subMenu:[
6738					{label:"하위메뉴1"},
6739					{label:"하위메뉴2",
6740						subMenu:[
6741							{label:"하위메뉴21"},
6742							{label:"하위메뉴22"}
6743						]
6744					},
6745					{label:"하위메뉴3"},
6746					{label:"하위메뉴3"},
6747					{label:"하위메뉴3"}
6748				]
6749			},
6750			{label:'선택 3', checked:true},
6751			{label:'선택 4', checked:false, sort:"asc"} // config 에 checkbox 가 있는데. menu에 onclick 가 없으면 체크박스 액션이 작동합니다.
6752		],
6753		onchange: function(){ // 체크박스 선택값이 변경 된 경우 호출 됩니다.
6754			trace(this.menu);
6755
6756			// return true; 메뉴 창이 닫히지 않게 합니다.
6757		},
6758		onsort: function(){ // 정렬이 변경 된 경우 호출 됩니다.
6759			trace(this.sortMenu);
6760
6761			// return true; 메뉴 창이 닫히지 않게 합니다.
6762		}
6763	});
6764```
6765 */
6766    bind: function (obj) {
6767        var cfg = this.config;
6768        if (!obj.id) {
6769            trace("ID가 없어 bind 처리할 수 없습니다. AXContentMenu.bind({id:'idValue'});");
6770            return;
6771        }
6772        var objSeq = null;
6773        axf.each(this.objects, function (idx, O) {
6774            if (this.id == obj.id) {
6775                objSeq = idx;
6776                return false;
6777            }
6778        });
6779
6780		if(!obj.reserveKeys){
6781			obj.reserveKeys = cfg.reserveKeys;
6782		}
6783        if (objSeq != null) {
6784            this.objects[objSeq] = obj;
6785            return this;
6786        }
6787        objSeq = this.objects.length;
6788
6789        this.objects.push(obj);
6790		return this;
6791    },
6792    filter: function (objSeq, objID, myobj, menu) {
6793        var cfg = this.config;
6794        var obj = this.objects[objSeq];
6795        if (myobj.filter) {
6796            var sendObj = {
6797                menu: menu,
6798                sendObj: obj.sendObj
6799            };
6800            return myobj.filter.call(sendObj, objID);
6801        } else {
6802            return true;
6803        }
6804    },
6805    getSubMenu: function (parentID, objSeq, objID, myobj, subMenu, depth) {
6806        var cfg = this.config;
6807        var obj = this.objects[objSeq];
6808
6809        var theme = obj.theme || cfg.theme;
6810        var width = obj.width || cfg.width;
6811
6812        var filter = this.filter.bind(this);
6813        var getSubMenu = this.getSubMenu.bind(this);
6814        var subMenuID = parentID + "_AX_subMenu";
6815
6816        var href = (obj.href == undefined) ? cfg.href : obj.href;
6817        var po = [];
6818        po.push("<div id=\"" + subMenuID + "\" class=\"" + theme + "\" style=\"width:" + width + "px;left:" + (width.number() - 15) + "px;display:none;\">");
6819        AXUtil.each(subMenu, function (idx, menu) {
6820            if (filter(objSeq, objID, myobj, menu)) {
6821                if (menu.upperLine) po.push("<div class=\"hline\"></div>");
6822                var className = (menu.className) ? menu.className : "";
6823                var hasSubMenu = (menu[obj.reserveKeys.subMenu]) ? " hasSubMenu" : "";
6824                po.push("<a " + href + " class=\"contextMenuItem " + className + hasSubMenu + "\" id=\"" + subMenuID + "_AX_" + depth + "_AX_" + idx + "\">");
6825                var checked = "";
6826                if(obj.checkbox){
6827                    if(menu.checked) checked = " on";
6828                    po.push("<div class='tool-checkbox"+ checked +"' id=\"" + subMenuID + "_tool_AX_" + depth + "_AX_" + idx + "\"></div>");
6829                }
6830
6831                po.push("<span class='label'>" + menu.label + "</span>");
6832
6833                if(menu.shotCut) po.push("<span class='shot-cut'>" + menu.shotCut + "</span>");
6834
6835                po.push("<div class='tool-rightGroup'>");
6836                if (menu[obj.reserveKeys.subMenu] && menu[obj.reserveKeys.subMenu].length > 0) po.push("<div class=\"contextSubMenuIcon\"></div>");
6837                po.push("</div>");
6838                po.push("</a>");
6839                menu.__axdomId = subMenuID + "_AX_" + depth + "_AX_" + idx;
6840
6841                if (menu[obj.reserveKeys.subMenu] && menu[obj.reserveKeys.subMenu].length > 0) po.push(getSubMenu(subMenuID + "_AX_" + depth + "_AX_" + idx, objSeq, objID, myobj, menu[obj.reserveKeys.subMenu], (depth + 1)));
6842                if (menu.underLine) po.push("<div class=\"hline\"></div>");
6843            }
6844        });
6845        po.push("</div>");
6846        return po.join('');
6847    },
6848/**
6849 * @method AXContextMenuClass.open
6850 * @param {Object} myobj
6851 * @param {Event|Object} position - 이벤트 객체를 전달하거나 {left:[Number], top:[Number]} 를 전달합니다.
6852 * @returns {AXContextMenuClass}
6853 * @description bind된 컨텍스트메뉴 개체를 오픈합니다. (이벤트속성에 정해진 마우스 포지션또는 사용자가 정한 left, top 포지션에)
6854 * @example
6855```js
6856AXContextMenu.open({
6857	id:"myContextMenuTree", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
6858}, event); // event 직접 연결 방식
6859
6860AXContextMenu.open({
6861	id:"myContextMenuTree", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
6862}, {left:0, top:0}); // position 직접 결정 방식
6863```
6864 */
6865    open: function (myobj, position) {
6866        var cfg = this.config;
6867        if(axf.clientWidth() < cfg.responsiveMobile){
6868            this.mobileOpen(myobj, position);
6869        }else{
6870            this.deskTopOpen(myobj, position);
6871        }
6872		return this;
6873    },
6874    mobileOpen: function(myobj, position){
6875        var cfg = this.config;
6876        var objSeq = null;
6877        AXUtil.each(this.objects, function (index, O) {
6878            if (O.id == myobj.id) {
6879                objSeq = index;
6880                return false;
6881            }
6882        });
6883        if (objSeq == null) {
6884            //trace("바인드 된 오브젝트를 찾을 수 없습니다.");
6885            return;
6886        }
6887        var obj = this.objects[objSeq];
6888        var objID = obj.id;
6889
6890        this.modal = new AXMobileModal();
6891        this.modal.setConfig({
6892            addClass:"",
6893            height: 388,
6894            width: 300,
6895            head:{
6896                //title:(myobj.title||AXConfig.AXContextMenu.title),
6897                close:{
6898                    onclick:function(){}
6899                }
6900            },
6901            onclose: function(){}
6902        });
6903
6904        var initMobileModalBind = this.initMobileModal.bind(this);
6905        var onLoad = function(modalObj){
6906            initMobileModalBind(objID, objSeq, myobj, modalObj);
6907        };
6908        this.modal.open(null, onLoad);
6909        this.mobileMode = true;
6910    },
6911    initMobileModal: function(objID, objSeq, myobj, modalObj){ // 현재 선택된 모바일 메뉴를 오픈합니다.
6912        var cfg = this.config, _this = this;
6913        var obj = this.objects[objSeq];
6914        this.mobileModalObj = {
6915            myobj:myobj,
6916            modalObj:modalObj
6917        }; // memo mobileModal
6918        if (myobj.sendObj) {
6919            obj.sendObj = myobj.sendObj;
6920        }
6921        var href = (obj.href == undefined) ? cfg.href : obj.href;
6922        var filter = this.filter.bind(this);
6923
6924        var headPo = [];
6925        /* 현재 선택된 메뉴 선택 하는 기능구현 필요 */
6926        headPo.push('<a ' + href + ' class="AXContextMenuHome">home</a>');
6927        headPo.push('<span id="' + objID + '_AX_mobileMenuPrevBox"></span>');
6928        modalObj.modalHead.empty();
6929        modalObj.modalHead.append(headPo.join(''));
6930
6931        modalObj.modalHead.find(".AXContextMenuHome").bind("click", function(){
6932            _this.initMobileModal(objID, objSeq, myobj, modalObj);
6933        });
6934
6935        var styles = [];
6936        styles.push("height:339px;");
6937        var menuList = obj.menu;
6938        var po = [];
6939        po.push("<div id=\"" + objID + "_AX_containerBox\" class=\"AXContextMenuContainer\" style=\"" + styles.join(";") + "\">");
6940        po.push("<div id=\"" + objID + "_AX_scroll\" class=\"AXContextMenuScroll\">");
6941
6942	    if(typeof obj.reserveKeys == "undefined"){
6943		    obj.reserveKeys = cfg.reserveKeys;
6944	    }
6945
6946        axf.each(menuList, function (idx, menu) {
6947            if (menu && filter(objSeq, objID, myobj, menu)) {
6948                //if (menu.upperLine) po.push("<div class=\"hline\"></div>");
6949                var className = (menu.className) ? " " + menu.className : "";
6950                var hasSubMenu = (menu[obj.reserveKeys.subMenu]) ? " hasSubMenu" : "";
6951                po.push("<a " + href + " class=\"contextMenuItem" + className + hasSubMenu + "\" id=\"" + objID + "_AX_contextMenu_AX_"+ 0 +"_AX_" + idx + "\">");
6952
6953                var checked = "";
6954                if(obj.checkbox){
6955                    if(menu.checked) checked = " on";
6956                    po.push("<div class='tool-checkbox"+ checked +"' id=\"" + objID + "_AX_contextMenuToolCheck_AX_"+ 0 +"_AX_" + idx + "\"></div>");
6957                }
6958
6959                po.push("<span class='label'>" + menu.label + "</label>");
6960
6961                if(menu.shotCut) po.push("<span class='shot-cut'>" + menu.shotCut + "</span>");
6962
6963                po.push("<div class='tool-rightGroup'>");
6964                if (menu[obj.reserveKeys.subMenu] && menu[obj.reserveKeys.subMenu].length > 0) po.push("<div class=\"contextSubMenuIcon\"></div>");
6965                if (obj.sortbox){
6966                    var sortdirect = "";
6967                    if(menu.sort){
6968                        sortdirect = " " + menu.sort.toString().lcase();
6969                    }
6970                    po.push("<div class=\"tool-sort"+ sortdirect +"\" id=\"" + objID + "_AX_contextMenuToolSort_AX_"+ 0 +"_AX_" + idx + "\"></div>");
6971                }
6972                po.push("</div>");
6973                po.push("</a>");
6974
6975                menu.__axdomId = objID + "_AX_contextMenu_AX_0_AX_" + idx;
6976                //if (menu.underLine) po.push("<div class=\"hline\"></div>");
6977            }
6978        });
6979        po.push("</div>");
6980        po.push("</div>");
6981
6982        modalObj.modalBody.empty();
6983        modalObj.modalBody.append(po.join(''));
6984
6985        this.myUIScroll = new AXScroll();
6986        this.myUIScroll.setConfig({
6987            targetID: objID + "_AX_containerBox",
6988            scrollID: objID + "_AX_scroll"
6989        });
6990
6991        var contextMenuItemClick = this.contextMenuItemClick.bind(this);
6992        var closeMobileModal = this.closeMobileModal.bind(this);
6993        this.contextMenuItemClickBind = function (event) {
6994            contextMenuItemClick(event, objSeq, objID);
6995            //closeMobileModal();
6996        };
6997        modalObj.modalBody.find(".contextMenuItem").bind("click", this.contextMenuItemClickBind);
6998    },
6999
7000    mobileModalSubMenu: function (parentID, objSeq, objID, myobj, modalObj, pMenu, depth) {
7001        var cfg = this.config, _this = this;
7002        var obj = this.objects[objSeq];
7003        var theme = obj.theme || cfg.theme;
7004        var width = obj.width || cfg.width;
7005
7006        var filter = this.filter.bind(this);
7007        var mobileModalSubMenu = this.mobileModalSubMenu.bind(this);
7008        var subMenuID = parentID + "_AX_subMenu";
7009
7010        var href = (obj.href == undefined) ? cfg.href : obj.href;
7011
7012        var poi = parentID.split(/_AX_/g);
7013        var pdepth = poi[poi.length - 2].number();
7014        /*
7015         if(pdepth == 0) {
7016         this.mobileModalObj.previousMenu = "root";
7017         this.mobileModalObj.nowMenu = pMenu.__axdomId;
7018         }else{
7019         this.mobileModalObj.previousMenu = this.mobileModalObj.nowMenu;
7020         this.mobileModalObj.nowMenu = pMenu.__axdomId;
7021         }
7022         */
7023        //trace(axdom("#" + objID + "_AX_mobileMenuPrevBox").get(0));
7024        axdom("#" + objID + "_AX_mobileMenuPrevBox").html('<a class="AXContextMenuPrev" id="'+objID+'_AX_prev_AX_'+poi.join("_")+'">'+pMenu.label+'</a>');
7025
7026        axdom("#"+objID+'_AX_prev_AX_'+poi.join("_")).bind("click", function(){
7027            if(pdepth == 0) {
7028                _this.initMobileModal(objID, objSeq, myobj, modalObj);
7029            }else{
7030                var poi = pMenu.__axdomId.split(/_AX_/g);
7031                var _depth = poi[poi.length - 2].number();
7032                var hashs = [];
7033
7034                var mystrPosition = poi.length - 1;
7035                for (var r = 0; r < depth + 1; r++) {
7036                    if(!isNaN(poi[mystrPosition])) hashs.push(poi[mystrPosition]);
7037                    mystrPosition -= 3;
7038                }
7039                hashs = hashs.reverse();
7040                hashs.pop();
7041                var menu = obj.menu;
7042                for (var hash, idx= 0, __arr = hashs; (idx < __arr.length && (hash = __arr[idx])); idx++) {
7043                    if (idx == 0) menu = menu[hash];
7044                    else menu = menu[obj.reserveKeys.subMenu][hash];
7045                }
7046                _this.mobileModalSubMenu(menu.__axdomId,  objSeq, objID,  _this.mobileModalObj.myobj, _this.mobileModalObj.modalObj, menu, (depth-1));
7047            }
7048        });
7049
7050        var styles = [];
7051        styles.push("height:339px;");
7052        var menuList = pMenu[obj.reserveKeys.subMenu];
7053        var po = [];
7054        po.push("<div id=\"" + objID + "_AX_containerBox\" class=\"AXContextMenuContainer\" style=\"" + styles.join(";") + "\">");
7055        po.push("<div id=\"" + objID + "_AX_scroll\" class=\"AXContextMenuScroll\">");
7056        axf.each(menuList, function (idx, menu) {
7057            if (menu && filter(objSeq, objID, myobj, menu)) {
7058                var className = (menu.className) ? " " + menu.className : "";
7059                var hasSubMenu = (menu[obj.reserveKeys.subMenu]) ? " hasSubMenu" : "";
7060                po.push("<a " + href + " class=\"contextMenuItem" + className + hasSubMenu + "\" id=\"" + subMenuID + "_AX_" + depth + "_AX_" + idx + "\">");
7061
7062                var checked = "";
7063                if(obj.checkbox){
7064                    if(menu.checked) checked = " on";
7065                    po.push("<div class='tool-checkbox"+ checked +"' id=\"" + subMenuID + "_AX_contextMenuToolCheck_AX_" + depth + "_AX_" + idx + "\"></div>");
7066                }
7067
7068                po.push("<span class='label'>" + menu.label + "</label>");
7069
7070                if(menu.shotCut) po.push("<span class='shot-cut'>" + menu.shotCut + "</span>");
7071
7072                po.push("<div class='tool-rightGroup'>");
7073                if (menu[obj.reserveKeys.subMenu] && menu[obj.reserveKeys.subMenu].length > 0) po.push("<div class=\"contextSubMenuIcon\"></div>");
7074                if (obj.sortbox){
7075                    var sortdirect = "";
7076                    if(menu.sort){
7077                        sortdirect = " " + menu.sort.toString().lcase();
7078                    }
7079                    po.push("<div class=\"tool-sort"+ sortdirect +"\" id=\"" + subMenuID + "_AX_contextMenuToolSort_AX_"+ depth +"_AX_" + idx + "\"></div>");
7080                }
7081                po.push("</div>");
7082
7083                po.push("</a>");
7084
7085                menu.__axdomId = subMenuID + "_AX_" + depth + "_AX_" + idx;
7086            }
7087        });
7088        po.push("</div>");
7089        po.push("</div>");
7090
7091        modalObj.modalBody.empty();
7092        modalObj.modalBody.append(po.join(''));
7093
7094        this.myUIScroll = new AXScroll();
7095        this.myUIScroll.setConfig({
7096            targetID: objID + "_AX_containerBox",
7097            scrollID: objID + "_AX_scroll"
7098        });
7099
7100        var contextMenuItemClick = this.contextMenuItemClick.bind(this);
7101        var closeMobileModal = this.closeMobileModal.bind(this);
7102        this.contextMenuItemClickBind = function (event) {
7103            contextMenuItemClick(event, objSeq, objID);
7104            //closeMobileModal();
7105        };
7106        modalObj.modalBody.find(".contextMenuItem").bind("click", this.contextMenuItemClickBind);
7107    },
7108
7109    closeMobileModal: function(){
7110        var cfg = this.config;
7111        this.modal.close();
7112    },
7113    deskTopOpen: function (myobj, position) {
7114        var cfg = this.config;
7115        var objSeq = null;
7116        this.mobileMode = false;
7117        AXUtil.each(this.objects, function (index, O) {
7118            if (O.id == myobj.id) {
7119                objSeq = index;
7120                return false;
7121            }
7122        });
7123        if (objSeq == null) {
7124            //trace("바인드 된 오브젝트를 찾을 수 없습니다.");
7125            return;
7126        }
7127        var obj = this.objects[objSeq];
7128        var objID = obj.id;
7129
7130        if (myobj.sendObj) {
7131            obj.sendObj = myobj.sendObj;
7132        }
7133
7134        if (AXgetId(objID)) return;
7135
7136        var theme = obj.theme || cfg.theme;
7137        var width = obj.width || cfg.width;
7138
7139        axdom("#" + objID).remove();
7140
7141        var href = (obj.href == undefined) ? cfg.href : obj.href;
7142
7143        var filter = this.filter.bind(this);
7144        var getSubMenu = this.getSubMenu.bind(this);
7145
7146        var displayMenuCount = 0;
7147        var po = [];
7148        po.push("<div id=\"" + objID + "\" class=\"" + theme + "\" style=\"width:" + width + "px;\">");
7149        AXUtil.each(obj.menu, function (idx, menu) {
7150            if (menu && filter(objSeq, objID, myobj, menu)) {
7151
7152                if (menu.upperLine) {
7153                    po.push("<div class=\"hline\"></div>");
7154                }
7155                var className = (menu.className) ? " " + menu.className : "";
7156                var hasSubMenu = (menu[obj.reserveKeys.subMenu]) ? " hasSubMenu" : "";
7157                po.push("<a " + href + " class=\"contextMenuItem" + className + hasSubMenu + "\" id=\"" + objID + "_AX_contextMenu_AX_0_AX_" + idx + "\">");
7158                var checked = "";
7159                if(obj.checkbox){
7160                    if(menu.checked) checked = " on";
7161                    po.push("<div class='tool-checkbox"+ checked +"' id=\"" + objID + "_AX_contextMenuTool_AX_0_AX_" + idx + "\"></div>");
7162                }
7163
7164                po.push("<span class='label'>" + menu.label + "</span>");
7165
7166                if(menu.shotCut) po.push("<span class='shot-cut'>" + menu.shotCut + "</span>");
7167
7168                po.push("<div class='tool-rightGroup'>");
7169                if (menu[obj.reserveKeys.subMenu] && menu[obj.reserveKeys.subMenu].length > 0) po.push("<div class=\"contextSubMenuIcon\"></div>");
7170                if (obj.sortbox)  po.push("<div class=\"tool_sort desc\"></div>");
7171                po.push("</div>");
7172                po.push("</a>");
7173
7174                menu.__axdomId = objID + "_AX_contextMenu_AX_0_AX_" + idx;
7175
7176                if (menu[obj.reserveKeys.subMenu]) {
7177                    if (menu[obj.reserveKeys.subMenu].length > 0) {
7178                        po.push(getSubMenu(objID + "_AX_contextMenu_AX_0_AX_" + idx, objSeq, objID, myobj, menu[obj.reserveKeys.subMenu], 1));
7179                    }
7180                }
7181                if (menu.underLine) {
7182                    po.push("<div class=\"hline\"></div>");
7183                }
7184                displayMenuCount++;
7185            }
7186        });
7187        po.push("</div>");
7188
7189        if(displayMenuCount == 0){
7190            // 표시할 메뉴가 없음.
7191            return false;
7192        }
7193        axdom(document.body).append(po.join(''));
7194
7195        axdom("#" + objID + " .contextMenuItem:first-child").addClass("first");
7196        axdom("#" + objID + " .contextMenuItem:last-child").addClass("last");
7197
7198        var contextMenuItemMouseOver = this.contextMenuItemMouseOver.bind(this);
7199        this.contextMenuItemMouseOverBind = function (event) {
7200            contextMenuItemMouseOver(event, objSeq, objID);
7201        };
7202        axdom("#" + objID + " .contextMenuItem").bind("mouseover", this.contextMenuItemMouseOverBind);
7203
7204        //컨텍스트 메뉴의 위치 지정
7205        var css = {};
7206        if (!position.clientX) {
7207            if (position.left != undefined) css.left = position.left;
7208            else css.right = position.right;
7209            css.top = position.top;
7210        } else {
7211            var mouse = this.getMousePositon(position);
7212            css.left = mouse.pageX;
7213            css.top = mouse.pageY;
7214        }
7215
7216        // -- 부모박스 정보와 박스 정보
7217        var pElement = axdom("#" + objID).offsetParent();
7218        var pBox = { width: pElement.width(), height: pElement.height() };
7219        var clientHeight = (AXUtil.docTD == "Q") ? document.body.scrollHeight : document.documentElement.scrollHeight;
7220        var clienWidth = (AXUtil.docTD == "Q") ? document.body.scrollWidth : document.documentElement.scrollWidth;
7221        if (clienWidth > pBox.width) pBox.width = clienWidth;
7222        if (clientHeight > pBox.height) pBox.height = clientHeight;
7223        var _box = { width: axdom("#" + objID).outerWidth(), height: axdom("#" + objID).outerHeight() };
7224        // -- 부모박스 정보와 박스 정보
7225
7226        if ((_box.height.number() + css.top.number()) > pBox.height) {
7227            css.top -= ((_box.height.number() + css.top.number()) - pBox.height) + 25;
7228            this.openTB = "up";
7229            if(css.top < 0) css.top = 0;
7230        }
7231
7232        if (css.left != undefined) {
7233
7234            if ((_box.width.number() + css.left.number()) > pBox.width) {
7235                var moveLeft = ((_box.width.number() + css.left.number()) - pBox.width) + 25;
7236                css.left -= moveLeft;
7237                this.openLR = "left";
7238            } else {
7239                if ((_box.width.number() * 2 + css.left.number()) > pBox.width) {
7240                    this.openLR = "left";
7241                }
7242            }
7243
7244            /*
7245             if((_box.width.number() + css.left.number()) > pBox.width){
7246             css.left -= ((_box.width.number() + css.left.number()) - pBox.width) + 5;
7247             this.openLR = "left";
7248             }
7249             */
7250        } else {
7251            css.left = "auto";
7252            this.openLR = "right";
7253        }
7254        axdom("#" + objID).css(css);
7255
7256        this.eventBind(objSeq, objID);
7257    },
7258    eventBind: function (objSeq, objID) {
7259        var cfg = this.config;
7260        /* closeEvent bind */
7261        var contextMenuItemDown = this.contextMenuItemDown.bind(this);
7262        var contextMenuItemDownBind = function (event) {
7263            contextMenuItemDown(event, objSeq, objID);
7264        };
7265
7266        axdom(document).bind("mousedown.AXContenxtMenu", contextMenuItemDownBind);
7267        axdom(document).bind("keydown.AXContenxtMenu", contextMenuItemDownBind);
7268
7269        axdom(document).find("iframe").each(function () {
7270            try{
7271                axdom(window[this.name].document).bind("mousedown.AXContenxtMenu", contextMenuItemDownBind);
7272                axdom(window[this.name].document).bind("keydown.AXContenxtMenu", contextMenuItemDownBind);
7273            }catch(e){
7274
7275            }
7276        });
7277
7278        /* closeEvent bind ~~~~~~~~~~~~~~~~~~~ */
7279        //click
7280        var contextMenuItemClick = this.contextMenuItemClick.bind(this);
7281        this.contextMenuItemClickBind = function (event) {
7282            contextMenuItemClick(event, objSeq, objID);
7283        };
7284        axdom("#" + objID).find(".contextMenuItem").bind("click", this.contextMenuItemClickBind);
7285    },
7286    // 이벤트로 인한 닫기
7287    _close: function (objSeq, objID) {
7288        var cfg = this.config,
7289            obj = this.objects[objSeq],
7290            that = {id:obj.id, event_type:"event"};
7291
7292        if(this.mobileMode){
7293            this.closeMobileModal();
7294        }else{
7295            axdom("#" + objID).fadeOut("fast", function () {
7296                axdom("#" + objID).remove();
7297            });
7298        }
7299
7300        axdom(document).unbind("keydown.AXContenxtMenu");
7301        axdom(document).unbind("mousedown.AXContenxtMenu");
7302
7303        axdom(document).find("iframe").each(function () {
7304	        if(window[this.name]){
7305		        axdom(window[this.name].document).unbind("mousedown.AXContenxtMenu");
7306		        axdom(window[this.name].document).unbind("keydown.AXContenxtMenu");
7307	        }
7308        });
7309
7310        this.showedItem = {}; // 초기화
7311        this.openTB = "";
7312        this.openLR = "";
7313
7314        if(obj.onclose){
7315            obj.onclose.call(that);
7316        }
7317    },
7318/**
7319 * @method AXContextMenuClass.close
7320 * @param {Object} obj
7321 * @returns {AXContextMenuClass}
7322 * @description 열린 컨텍스트메뉴 개체를 닫습니다.
7323 * @example
7324```js
7325AXContextMenu.close({
7326	id:"myContextMenuTree"
7327});
7328```
7329 */
7330    close: function (myobj) {
7331        var cfg = this.config,
7332            objSeq = null;
7333
7334        axf.each(this.objects, function (index, O) {
7335            if (O.id == myobj.id) {
7336                objSeq = index;
7337                return false;
7338            }
7339        });
7340        if (objSeq == null) {
7341            //trace("바인드 된 오브젝트를 찾을 수 없습니다.");
7342            return;
7343        }
7344
7345        var obj = this.objects[objSeq], objID = obj.id,
7346            that = {id:obj.id, event_type:"script"};
7347
7348        if(this.mobileMode){
7349            this.closeMobileModal();
7350        }else{
7351            axdom("#" + objID).fadeOut("fast", function () {
7352                axdom("#" + objID).remove();
7353            });
7354        }
7355
7356        axdom(document).unbind("keydown", this.contextMenuItemDownBind);
7357        axdom(document).unbind("mousedown", this.contextMenuItemDownBind);
7358
7359        this.showedItem = {}; // 초기화
7360        this.openTB = "";
7361        this.openLR = "";
7362
7363        if(obj.onclose){
7364
7365        }
7366
7367		return this;
7368    },
7369    contextMenuItemMouseOver: function (event, objSeq, objID) {
7370        var cfg = this.config;
7371        var obj = this.objects[objSeq];
7372
7373        var menuWidth = obj.width || cfg.width;
7374        // event target search -
7375        var eid = event.target.id.split(/_AX_/g);
7376        var eventTarget = event.target;
7377        var myTarget = this.getEventTarget({
7378            evt: eventTarget, evtIDs: eid,
7379            find: function (evt, evtIDs) { return (axdom(evt).hasClass("contextMenuItem")) ? true : false; }
7380        });
7381        // event target search ------------------------
7382        if (myTarget) {
7383            var poi = myTarget.id.split(/_AX_/g);
7384            var depth = poi[poi.length - 2];
7385            if (this.showedItem[depth]) {
7386                axdom("#" + this.showedItem[depth]).hide();
7387            }
7388            if (axdom(myTarget).hasClass("hasSubMenu")) {
7389
7390                // -- 부모박스 정보와 박스 정보
7391                var pElement = axdom("#" + myTarget.id + "_AX_subMenu").offsetParent();
7392                var pBox = { width: pElement.width(), height: pElement.height() };
7393                var clientHeight = (AXUtil.docTD == "Q") ? document.body.scrollHeight : document.documentElement.scrollHeight;
7394                var clienWidth = (AXUtil.docTD == "Q") ? document.body.scrollWidth : document.documentElement.scrollWidth;
7395                if (clienWidth > pBox.width) pBox.width = clienWidth;
7396                if (clientHeight > pBox.height) pBox.height = clientHeight;
7397                var _box = { width: axdom("#" + myTarget.id + "_AX_subMenu").outerWidth(), height: axdom("#" + myTarget.id + "_AX_subMenu").outerHeight() };
7398                // -- 부모박스 정보와 박스 정보
7399
7400                var subMenuTop = axdom("#" + myTarget.id).position().top;
7401
7402                var css;
7403                if (this.openTB == "up") {
7404                    var ph = axdom("#" + myTarget.id).offsetParent().height();
7405                    var h = axdom("#" + myTarget.id).height();
7406                    var bottom = ph - subMenuTop - h;
7407                    css = { top: "auto", bottom: bottom };
7408                } else {
7409                    css = { top: subMenuTop };
7410                }
7411                if (this.openLR == "left") {
7412                    //css.left = -(menuWidth - 15);
7413                    css.left = -(20);
7414                }
7415
7416                axdom("#" + myTarget.id + "_AX_subMenu").css(css);
7417                axdom("#" + myTarget.id + "_AX_subMenu").show();
7418
7419                this.showedItem[depth] = myTarget.id + "_AX_subMenu";
7420            }
7421        }
7422    },
7423    contextMenuItemDown: function (event, objSeq, objID) {
7424        var cfg = this.config;
7425        var obj = this.objects[objSeq];
7426
7427        if (event.keyCode == AXUtil.Event.KEY_ESC) {
7428            this._close(objSeq, objID, event);
7429            return;
7430        }
7431
7432        // event target search -
7433        var eid = event.target.id.split(/_AX_/g);
7434        var eventTarget = event.target;
7435        var myTarget = this.getEventTarget({
7436            evt: eventTarget, evtIDs: eid,
7437            find: function (evt, evtIDs) { return (axdom(evt).hasClass("contextMenuItem")) ? true : false; }
7438        });
7439        // event target search ------------------------
7440
7441        if (myTarget) {
7442
7443        } else {
7444            this._close(objSeq, objID, event);
7445        }
7446    },
7447    contextMenuItemClick: function (event, objSeq, objID) {
7448        var cfg = this.config;
7449        var obj = this.objects[objSeq];
7450
7451        // event target search -
7452        var eid = event.target.id.split(/_AX_/g);
7453        var eventTarget = event.target;
7454        var myTarget = this.getEventTarget({
7455            evt: eventTarget, evtIDs: eid,
7456            find: function (evt, evtIDs) { return (axdom(evt).hasClass("contextMenuItem") || axdom(evt).hasClass("tool-checkbox") || axdom(evt).hasClass("tool-sort")) ? true : false; }
7457        });
7458        // event target search ------------------------
7459
7460        if (myTarget) {
7461
7462            var poi = myTarget.id.split(/_AX_/g);
7463            var depth = poi[poi.length - 2].number();
7464            var hashs = [];
7465
7466            var mystrPosition = poi.length - 1;
7467            for (var r = 0; r < depth + 1; r++) {
7468                hashs.push(poi[mystrPosition]);
7469                mystrPosition -= 3;
7470            }
7471            hashs = hashs.reverse();
7472
7473            var menu = obj.menu;
7474            for (var hash, idx= 0, __arr = hashs; (idx < __arr.length && (hash = __arr[idx])); idx++) {
7475                if (idx == 0) menu = menu[hash];
7476                else menu = menu[obj.reserveKeys.subMenu][hash];
7477            }
7478
7479            if (menu[obj.reserveKeys.subMenu] && menu[obj.reserveKeys.subMenu].length > 0 && this.mobileMode){
7480                //this.initMobileModal(objID, objSeq, this.mobileModalObj.myobj, this.mobileModalObj.modalObj, (depth+1), menu.subMenu);
7481                this.mobileModalSubMenu(myTarget.id,  objSeq, objID,  this.mobileModalObj.myobj, this.mobileModalObj.modalObj, menu, (depth+1));
7482                return false;
7483            }
7484
7485            if (axdom(myTarget).hasClass("tool-checkbox")){
7486                menu.checked = !menu.checked;
7487                axdom("#" + menu.__axdomId).find(".tool-checkbox").toggleClass("on");
7488
7489                if (obj.onchange) {
7490                    obj.onchange.call({ menu: obj.menu, clickMenu: menu, sendObj: obj.sendObj }, objID);
7491                }
7492                return true;
7493            }
7494
7495            if (axdom(myTarget).hasClass("tool-sort")){
7496
7497                // 다른 메뉴들은 모두 정렬 헤제
7498                for (var M, midx= 0, __arr = obj.menu; (midx < __arr.length && (M = __arr[midx])); midx++) {
7499                    if(menu != M){
7500                        M.sort = undefined;
7501                        axdom("#" + M.__axdomId).find(".tool-sort").removeClass("asc").removeClass("desc");
7502                    }
7503                }
7504
7505
7506                if(menu.sort == undefined) menu.sort = "";
7507                if(menu.sort.toString().lcase() == "asc"){
7508                    axdom("#" + menu.__axdomId).find(".tool-sort").removeClass("asc").addClass("desc");
7509                    menu.sort = "desc";
7510                }else if(menu.sort.toString().lcase() == "desc"){
7511                    axdom("#" + menu.__axdomId).find(".tool-sort").removeClass("desc").addClass("asc");
7512                    menu.sort = "asc";
7513                }else{
7514                    axdom("#" + menu.__axdomId).find(".tool-sort").addClass("desc");
7515                    menu.sort = "desc";
7516                }
7517
7518                if (obj.onsort) {
7519                    if(obj.onsort.call({ menu: obj.menu, sortMenu: menu, sendObj: obj.sendObj }, objID) != true){
7520                        this._close(objSeq, objID, event);
7521                    }
7522                }
7523                return true;
7524            }
7525
7526            if (menu.onclick) {
7527                if(menu.onclick.call({ menu: menu, sendObj: obj.sendObj }, objID) != true){
7528                    this._close(objSeq, objID, event);
7529                }
7530                return true;
7531            }else if (obj.onchange) { // 라벨 선택 할 때. 정렬항목도 없는 경우만 체크 모드로 연결
7532                menu.checked = !menu.checked;
7533                axdom("#" + menu.__axdomId).find(".tool-checkbox").toggleClass("on");
7534
7535                if (obj.onchange) {
7536                    if (obj.onchange.call({ menu: obj.menu, clickMenu: menu, sendObj: obj.sendObj }, objID) != true){
7537                        this._close(objSeq, objID, event);
7538                    }
7539                }
7540                return true;
7541            }
7542        }
7543    }
7544});
7545
7546var AXContextMenu = new AXContextMenuClass();
7547AXContextMenu.setConfig({});
7548
7549/**
7550 * @namespace AXContextMenu
7551 * @description AXContextMenu 오브젝트는 AXContextMenuClass 를 이용하여 AXJ에서 미리 선언한 인스턴스입니다.
7552 * AXContentMenu와 같이 사용할 때마다 new를 하지 않고 사용되는 UI들은 AXJ에서 미리 선언해두고 있습니다.
7553 */
7554/**
7555 * @method AXContextMenu.bindSetConfig
7556 * @param {String} objID - object ID
7557 * @param {Object} configs - contentMenu config
7558 * @description contextmenu 오브젝트에 속성을 변경합니다.
7559 * @example
7560 ```js
7561 AXContextMenu.bindSetConfig("contenxt01", {});
7562 ```
7563 */
7564/**
7565 * @method AXContextMenu.bind
7566 * @param {Object} obj - 컨텍스트메뉴 속성
7567 * @returns {AXContextMenu}
7568 * @description 컨텍스트메뉴를 선언하여 컨텍스트를 메뉴를 사용준비합니다. bind한 컨텍스트 메뉴는 id로 open 할 수 있습니다.
7569 * @example
7570 ```js
7571 AXContextMenu.bind({
7572		id:"myContextMenu",
7573		theme:"AXContextMenu", // 선택항목
7574		width:"150", // 선택항목
7575		checkbox:"checkbox", // [checkbox|radio]
7576		sortbox:true,
7577		menu:[
7578			{label:'선택 1', checked:true, onclick:function(){
7579				return false;
7580			}},
7581			{label:'선택 2', checked:true,
7582				subMenu:[
7583					{label:"하위메뉴1"},
7584					{label:"하위메뉴2",
7585						subMenu:[
7586							{label:"하위메뉴21"},
7587							{label:"하위메뉴22"}
7588						]
7589					},
7590					{label:"하위메뉴3"},
7591					{label:"하위메뉴3"},
7592					{label:"하위메뉴3"}
7593				]
7594			},
7595			{label:'선택 3', checked:true},
7596			{label:'선택 4', checked:false, sort:"asc"} // config 에 checkbox 가 있는데. menu에 onclick 가 없으면 체크박스 액션이 작동합니다.
7597		],
7598		onchange: function(){ // 체크박스 선택값이 변경 된 경우 호출 됩니다.
7599			trace(this.menu);
7600
7601			// return true; 메뉴 창이 닫히지 않게 합니다.
7602		},
7603		onsort: function(){ // 정렬이 변경 된 경우 호출 됩니다.
7604			trace(this.sortMenu);
7605
7606			// return true; 메뉴 창이 닫히지 않게 합니다.
7607		}
7608	});
7609 ```
7610 */
7611/**
7612 * @method AXContextMenu.open
7613 * @param {Object} myobj
7614 * @param {Event|Object} position - 이벤트 객체를 전달하거나 {left:[Number], top:[Number]} 를 전달합니다.
7615 * @returns {AXContextMenu}
7616 * @description bind된 컨텍스트메뉴 개체를 오픈합니다. (이벤트속성에 정해진 마우스 포지션또는 사용자가 정한 left, top 포지션에)
7617 * @example
7618 ```js
7619 AXContextMenu.open({
7620	id:"myContextMenuTree", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
7621}, event); // event 직접 연결 방식
7622
7623 AXContextMenu.open({
7624	id:"myContextMenuTree", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
7625}, {left:0, top:0}); // position 직접 결정 방식
7626 ```
7627 */
7628/**
7629 * @method AXContextMenu.close
7630 * @param {Object} obj
7631 * @returns {AXContextMenu}
7632 * @description 열린 컨텍스트메뉴 개체를 닫습니다.
7633 * @example
7634 ```js
7635 AXContextMenu.close({
7636	id:"myContextMenuTree"
7637});
7638 ```
7639 */
7640
7641
7642/**
7643 * @class AXPopOverClass
7644 * @extends AXContextMenuClass
7645 * @version v1.0
7646 * @author [email protected], axisj.com
7647 * @description AXContextMenuClass를 상속하여 만들어진 클래스로 마우스 오버이벤트에 최적화 됨
7648 * @example
7649```js
7650 var AXPopOver = new AXPopOverClass();
7651 AXPopOver.setConfig({ theme: "AXPopOver" });
7652```
7653 */
7654var AXPopOverClass = Class.create(AXContextMenuClass, {
7655/**
7656 * @method AXPopOverClass.bind
7657 * @param {Object} obj 팝오버메뉴 속성
7658 * @returns AXPopOverClass
7659 * @description 팝오버메뉴를 선언하여 팝오버 메뉴를 사용준비합니다. bind한 팝오버메뉴는 id로 open 할 수 있습니다.
7660 * @example
7661 ```js
7662 AXPopOver.bind({
7663	id:"myPopOver",
7664	theme:"AXPopOver", // 선택항목
7665	width:"200", // 선택항목
7666	menu:[
7667		{userType:0, label:"Friends", className:"groupName"},
7668		{userType:0, label:"Invite friends", className:"", onclick:function(){}},
7669		{userType:0, label:"Find friends", className:"", onclick:function(){}},
7670		{userType:0, label:"Photo", className:"groupName"},
7671		{userType:0, label:"Cut", className:"", onclick:function(){}},
7672		{userType:0, label:"Roll", className:"", onclick:function(){}},
7673		{userType:0, label:"Equipment", className:"groupName"},
7674		{userType:0, label:"Setting", className:""},
7675		{userType:0, label:"Screen", className:"", onclick:function(){}},
7676		{userType:0, label:"Securities", className:"groupName"},
7677		{userType:0, label:"Account", className:"", onclick:function(){}},
7678		{userType:0, label:"Logout", className:"", onclick:function(){}},
7679	]
7680});
7681
7682 $("#popoverBtn1").bind("mouseover", function(){
7683	var pos = $(this).offset();
7684	AXPopOver.open({
7685		id:"myPopOver", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}},
7686		{left:pos.left-60, top:pos.top+30}
7687	);
7688});
7689 ```
7690 */
7691
7692/**
7693 * @method AXPopOverClass.open
7694 * @param {Object} myobj
7695 * @param {Event|Object} position - 이벤트 객체를 전달하거나 {left:[Number], top:[Number]} 를 전달합니다.
7696 * @returns {AXPopOverClass}
7697 * @description bind된 컨텍스트메뉴 개체를 오픈합니다. (이벤트속성에 정해진 마우스 포지션또는 사용자가 정한 left, top 포지션에)
7698 * @example
7699 ```js
7700 AXPopOver.open({
7701	id:"myPopover", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
7702}, event); // event 직접 연결 방식
7703
7704 AXPopOver.open({
7705	id:"myPopover", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
7706}, {left:0, top:0}); // position 직접 결정 방식
7707 ```
7708 */
7709
7710/**
7711 * @method AXPopOverClass.close
7712 * @param {Object} obj
7713 * @returns {AXPopOverClass}
7714 * @description 열린 팝오버메뉴 개체를 닫습니다.
7715 * @example
7716 ```js
7717 AXPopOver.close({
7718	id:"myPopOver"
7719});
7720 ```
7721 */
7722    open: function (myobj, position) {
7723        var cfg = this.config;
7724        var objSeq = null;
7725        AXUtil.each(this.objects, function (index, O) {
7726            if (O.id == myobj.id) {
7727                objSeq = index;
7728                //return false;
7729            } else {
7730                axdom("#" + O.id).remove();
7731            }
7732        });
7733        if (objSeq == null) {
7734            //trace("바인드 된 오브젝트를 찾을 수 없습니다.");
7735            return;
7736        }
7737
7738        var obj = this.objects[objSeq];
7739        var objID = obj.id;
7740
7741        if (myobj.sendObj) {
7742            obj.sendObj = myobj.sendObj;
7743        }
7744
7745        if (this.observer) clearTimeout(this.observer); //닫기 명령 제거
7746        var direction = obj.direction || "top";
7747
7748        if (AXgetId(objID)) {
7749            if (position.clientX) {
7750                this.contentMenuSetCss(event, position, objSeq, objID);
7751            }
7752            return;
7753        }
7754
7755        var theme = obj.theme || cfg.theme;
7756        var width = obj.width || cfg.width;
7757
7758        //컨텍스트 메뉴의 위치 지정
7759
7760        var arrowStyle = "";
7761        if (position.clientX) {
7762            arrowStyle = "background-position:10px 0px;"
7763        } else {
7764            if (position.arrowLeft) arrowStyle = "background-position:" + position.arrowLeft + "px 0px;"
7765        }
7766
7767        axdom("#" + objID).remove();
7768
7769        var href = (obj.href == undefined) ? cfg.href : obj.href;
7770
7771        var filter = this.filter.bind(this);
7772        var getSubMenu = this.getSubMenu.bind(this);
7773        var po = [];
7774        po.push("<div id=\"" + objID + "\" class=\"" + theme + "\" style=\"width:" + width + "px;\">");
7775        po.push("<div class=\"arrowTop\" style=\"" + arrowStyle + "\"></div>");
7776        po.push("<div class=\"arrowBottom\" style=\"" + arrowStyle + "\"></div>");
7777        po.push("<div class=\"blockContainer\">");
7778        if (obj.menu) {
7779            AXUtil.each(obj.menu, function (idx, menu) {
7780                if (!menu) return false;
7781                if (filter(objSeq, objID, myobj, menu)) {
7782                    if (menu.upperLine) {
7783                        po.push("<div class=\"hline\"></div>");
7784                    }
7785                    var className = (menu.className) ? " " + menu.className : "";
7786                    var hasSubMenu = (menu.subMenu) ? " hasSubMenu" : "";
7787                    po.push("<a " + href + " class=\"contextMenuItem" + className + hasSubMenu + "\" id=\"" + objID + "_AX_contextMenu_AX_0_AX_" + idx + "\">");
7788                    po.push(menu.label);
7789                    if (menu.subMenu) {
7790                        if (menu.subMenu.length > 0) {
7791                            po.push("<div class=\"contextSubMenuIcon\"></div>");
7792                        }
7793                    }
7794                    po.push("</a>");
7795                    if (menu.subMenu) {
7796                        if (menu.subMenu.length > 0) {
7797                            po.push(getSubMenu(objID + "_AX_contextMenu_AX_0_AX_" + idx, objSeq, objID, myobj, menu.subMenu, 1));
7798                        }
7799                    }
7800                    if (menu.underLine) {
7801                        po.push("<div class=\"hline\"></div>");
7802                    }
7803                }
7804            });
7805        } else if (obj.body) {
7806            po.push("<div class=\"contextMenuBody\">");
7807            po.push(obj.body);
7808            po.push("</div>");
7809        }
7810        po.push("</div>");
7811        po.push("</div>");
7812        axdom(document.body).append(po.join(''));
7813
7814        if (direction == "top") {
7815            axdom("#" + objID).find(".arrowTop").show();
7816            axdom("#" + objID).find(".arrowBottom").hide();
7817        } else if (direction == "bottom") {
7818            axdom("#" + objID).find(".arrowTop").hide();
7819            axdom("#" + objID).find(".arrowBottom").show();
7820        } else {
7821            axdom("#" + objID).find(".arrowTop").show();
7822            axdom("#" + objID).find(".arrowBottom").hide();
7823        }
7824
7825        axdom("#" + objID + " .contextMenuItem:first-child").addClass("first");
7826        axdom("#" + objID + " .contextMenuItem:last-child").addClass("last");
7827
7828        var contextMenuItemMouseOver = this.contextMenuItemMouseOver.bind(this);
7829        this.contextMenuItemMouseOverBind = function (event) {
7830            contextMenuItemMouseOver(event, objSeq, objID);
7831        };
7832        var contextMenuMouseOut = this.contextMenuMouseOut.bind(this);
7833        this.contextMenuMouseOutBind = function (event) {
7834            contextMenuMouseOut(event, objSeq, objID);
7835        };
7836
7837        var eventClear = function () {
7838            if (this.observer) clearTimeout(this.observer); //닫기 명령 제거
7839        }
7840        axdom("#" + objID + " .contextMenuItem").bind("mouseover", this.contextMenuItemMouseOverBind);
7841        axdom("#" + objID).bind("mouseover", eventClear.bind(this));
7842        axdom("#" + objID).bind("mouseout", this.contextMenuMouseOutBind);
7843
7844        this.contentMenuSetCss(null, position, objSeq, objID);
7845
7846        //var eventBind = this.eventBind.bind(this);
7847        this.eventBind(objSeq, objID);
7848        //setTimeout(function(){}, 1);
7849
7850		return this;
7851    },
7852    contentMenuSetCss: function (event, position, objSeq, objID) {
7853        var cfg = this.config;
7854        var obj = this.objects[objSeq];
7855        var direction = obj.direction || "top";
7856        var css = {};
7857
7858        if (!position.clientX) {
7859            if (position.left != undefined) {
7860                css.left = position.left;
7861            } else {
7862                css.left = "auto";
7863                css.right = position.right;
7864            }
7865            css.top = position.top;
7866        } else {
7867            var mouse = this.getMousePositon(position);
7868            obj.eventPosition = true;
7869            css.left = mouse.pageX;
7870            css.left -= 20;
7871            css.top = mouse.pageY;
7872        }
7873        // -- 부모박스 정보와 박스 정보
7874        var pElement = axdom("#" + objID).offsetParent();
7875        var pBox = { width: pElement.width(), height: pElement.height() };
7876        var clientHeight = (AXUtil.docTD == "Q") ? document.body.scrollHeight : document.documentElement.scrollHeight;
7877        var clienWidth = (AXUtil.docTD == "Q") ? document.body.scrollWidth : document.documentElement.scrollWidth;
7878        if (clienWidth > pBox.width) pBox.width = clienWidth;
7879        if (clientHeight > pBox.height) pBox.height = clientHeight;
7880        var _box = { width: axdom("#" + objID).outerWidth(), height: axdom("#" + objID).outerHeight() };
7881        // -- 부모박스 정보와 박스 정보
7882        var openTB = "";
7883        if (direction == "top") {
7884            openTB = "top";
7885        } else if (direction == "bottom") {
7886            css.top -= axdom("#" + objID).outerHeight();
7887            openTB = "bottom";
7888        } else {
7889            if ((_box.height.number() + css.top.number()) > pBox.height) {
7890                css.top = css.top - _box.height.number() - position.handleHeight - 3;
7891                axdom("#" + objID).find(".arrowTop").hide();
7892                axdom("#" + objID).find(".arrowBottom").show();
7893                //css.top -= ((_box.height.number() + css.top.number()) - pBox.height) + 5;
7894                openTB = "bottom";
7895            } else {
7896                axdom("#" + objID).find(".arrowTop").show();
7897                axdom("#" + objID).find(".arrowBottom").hide();
7898                openTB = "top";
7899            }
7900        }
7901
7902        if (css.left != undefined) {
7903            if ((_box.width.number() + css.left.number()) > pBox.width) {
7904                var moveLeft = ((_box.width.number() + css.left.number()) - pBox.width) + 5;
7905                css.left -= moveLeft;
7906                if (openTB == "top") {
7907                    axdom("#" + objID).find(".arrowTop").css({ "background-position": (moveLeft + 5) + "px 0px;" });
7908                } else {
7909                    axdom("#" + objID).find(".arrowBottom").css({ "background-position": (moveLeft + 5) + "px 0px;" });
7910                }
7911            } else {
7912
7913            }
7914        } else {
7915
7916        }
7917        axdom("#" + objID).css(css);
7918    },
7919    contextMenuItemMouseOver: function (event, objSeq, objID) {
7920        var cfg = this.config;
7921        var obj = this.objects[objSeq];
7922
7923        if (this.observer) clearTimeout(this.observer); //닫기 명령 제거
7924
7925        var menuWidth = obj.width || cfg.width;
7926        // event target search -
7927        var eid = event.target.id.split(/_AX_/g);
7928        var eventTarget = event.target;
7929        var myTarget = this.getEventTarget({
7930            evt: eventTarget, evtIDs: eid,
7931            find: function (evt, evtIDs) { return (axdom(evt).hasClass("contextMenuItem")) ? true : false; }
7932        });
7933        // event target search ------------------------
7934        if (myTarget) {
7935            var poi = myTarget.id.split(/_AX_/g);
7936            var depth = poi[poi.length - 2];
7937            if (this.showedItem[depth]) {
7938                axdom("#" + this.showedItem[depth]).hide();
7939            }
7940            if (axdom(myTarget).hasClass("hasSubMenu")) {
7941                var subMenuTop = axdom("#" + myTarget.id).position().top;
7942                var css;
7943                if (this.openTB == "up") {
7944                    var ph = axdom("#" + myTarget.id).offsetParent().height();
7945                    var h = axdom("#" + myTarget.id).height();
7946                    var bottom = ph - subMenuTop - h;
7947                    css = { top: "auto", bottom: bottom };
7948                } else {
7949                    css = { top: subMenuTop };
7950                }
7951                if (this.openLR == "left") {
7952                    //css.left = -(menuWidth - 15);
7953                    css.left = -(20);
7954                }
7955                axdom("#" + myTarget.id + "_AX_subMenu").css(css);
7956                axdom("#" + myTarget.id + "_AX_subMenu").show();
7957
7958                this.showedItem[depth] = myTarget.id + "_AX_subMenu";
7959            }
7960        }
7961    },
7962    contextMenuMouseOut: function (event, objSeq, objID) {
7963        var close = this._close.bind(this);
7964        this.observer = setTimeout(function () {
7965            close(objSeq, objID);
7966        }, 200);
7967    }
7968});
7969var AXPopOver = new AXPopOverClass();
7970AXPopOver.setConfig({ theme: "AXPopOver" });
7971
7972/**
7973 * @namespace AXPopOver
7974 * @description AXPopOver 오브젝트는 AXPopOverClass 를 이용하여 AXJ에서 미리 선언한 인스턴스입니다.
7975 * AXPopOver 같이 사용할 때마다 new를 하지 않고 사용되는 UI들은 AXJ에서 미리 선언해두고 있습니다.
7976 */
7977/**
7978 * @method AXPopOver.bindSetConfig
7979 * @param {String} objID - object ID
7980 * @param {Object} configs contentMenu config
7981 * @description contextmenu 오브젝트에 속성을 변경합니다.
7982 * @example
7983 ```js
7984 AXPopOver.bindSetConfig("popover01", {});
7985 ```
7986 */
7987/**
7988 * @method AXPopOver.bind
7989 * @param {Object} obj - 컨텍스트메뉴 속성
7990 * @returns {AXPopOver}
7991 * @description 컨텍스트메뉴를 선언하여 컨텍스트를 메뉴를 사용준비합니다. bind한 컨텍스트 메뉴는 id로 open 할 수 있습니다.
7992 * @example
7993 ```js
7994 AXPopOver.bind({
7995	id:"myPopOver",
7996	theme:"AXPopOver", // 선택항목
7997	width:"200", // 선택항목
7998	menu:[
7999		{userType:0, label:"Friends", className:"groupName"},
8000		{userType:0, label:"Invite friends", className:"", onclick:function(){}},
8001		{userType:0, label:"Find friends", className:"", onclick:function(){}},
8002		{userType:0, label:"Photo", className:"groupName"},
8003		{userType:0, label:"Cut", className:"", onclick:function(){}},
8004		{userType:0, label:"Roll", className:"", onclick:function(){}},
8005		{userType:0, label:"Equipment", className:"groupName"},
8006		{userType:0, label:"Setting", className:""},
8007		{userType:0, label:"Screen", className:"", onclick:function(){}},
8008		{userType:0, label:"Securities", className:"groupName"},
8009		{userType:0, label:"Account", className:"", onclick:function(){}},
8010		{userType:0, label:"Logout", className:"", onclick:function(){}},
8011	]
8012});
8013
8014 $("#popoverBtn1").bind("mouseover", function(){
8015	var pos = $(this).offset();
8016	AXPopOver.open({
8017		id:"myPopOver", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}},
8018		{left:pos.left-60, top:pos.top+30}
8019	);
8020});
8021 ```
8022 */
8023/**
8024 * @method AXPopOver.open
8025 * @param {Object} myobj
8026 * @param {Event|Object} position - 이벤트 객체를 전달하거나 {left:[Number], top:[Number]} 를 전달합니다.
8027 * @returns {AXPopOver}
8028 * @description bind된 컨텍스트메뉴 개체를 오픈합니다. (이벤트속성에 정해진 마우스 포지션또는 사용자가 정한 left, top 포지션에)
8029 * @example
8030 ```js
8031 AXPopOver.open({
8032	id:"myPopover", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
8033}, event); // event 직접 연결 방식
8034
8035 AXPopOver.open({
8036	id:"myPopover", sendObj:{id:"전달하고싶은 오브젝트", name:"형식은 자유"}
8037}, {left:0, top:0}); // position 직접 결정 방식
8038 ```
8039 */
8040/**
8041 * @method AXPopOver.close
8042 * @param {Object} obj
8043 * @returns {AXPopOver}
8044 * @description 열린 팝오버 개체를 닫습니다.
8045 * @example
8046 ```js
8047 AXPopOver.close({
8048	id:"myPopover"
8049});
8050 ```
8051 */
8052
8053
8054/**
8055 * @method jQueryExtends.bindTooltip
8056 * @param {Object} configs - 툴팁설정
8057 * @returns {jQueryObject}
8058 * @description 툴팁을 바인드 하는 대상의 '아이디+"_AX_tooltip"'를 아이디로 하는 엘리먼트를 대상이 마우스 오버 이벤트 발생 할때 툴팁으로 표시 합니다.
8059 * @example
8060```js
8061
8062 <div style="position:relative;">
8063	 <button class="AXButton" onclick="" id="tooltip4"><div class="black_help">Bottom</div></button>
8064	 <div id="tooltip4_AX_tooltip" class="AXTooltipContent">
8065		 AXCore 에서는 자바스크립트 자료형에 대한 prototype 확장 메소드,
8066		 AXJ 클래스 원형, AXUtil 개체, AXReq(AJAX통신용) 클래스, AXCalendar 클래스, AXContext 클래스, AXPopOver 클래스, AXMask 클래스, AXNotification 클래스,
8067		 AXScroll 클래스, AXMultiSelect 클래스, jQuery extend(eventType, easing) 구문 등을 포함하고 있습니다.
8068	 </div>
8069
8070	 <button class="AXButton" onclick="" id="tooltip5"><div class="black_help">Top</div></button>
8071	 <div id="tooltip5_AX_tooltip" class="AXTooltipContent">
8072		 AXCore 에서는 자바스크립트 자료형에 대한 prototype 확장 메소드,
8073		 AXJ 클래스 원형, AXUtil 개체, AXReq(AJAX통신용) 클래스, AXCalendar 클래스, AXContext 클래스, AXPopOver 클래스, AXMask 클래스, AXNotification 클래스,
8074		 AXScroll 클래스, AXMultiSelect 클래스, jQuery extend(eventType, easing) 구문 등을 포함하고 있습니다.
8075	 </div>
8076
8077	 <button class="AXButton" onclick="" id="tooltip6"><div class="black_help">Auto</div></button>
8078	 <div id="tooltip6_AX_tooltip" class="AXTooltipContent">
8079		 AXCore 에서는 자바스크립트 자료형에 대한 prototype 확장 메소드,
8080		 AXJ 클래스 원형, AXUtil 개체, AXReq(AJAX통신용) 클래스, AXCalendar 클래스, AXContext 클래스, AXPopOver 클래스, AXMask 클래스, AXNotification 클래스,
8081		 AXScroll 클래스, AXMultiSelect 클래스, jQuery extend(eventType, easing) 구문 등을 포함하고 있습니다.
8082	 </div>
8083 </div>
8084 <script>
8085	// configs:{
8086	//	theme: (config.theme || "AXPopOverTooltip"), // (optional)
8087	//	width: (config.width || ""), // (optional)
8088	//	direction: (config.direction || "top"), // (optional)
8089	// }
8090
8091	// class 가 tooltipbind인 모든 엘리먼트에 툴팁설정
8092	$(".tooltipbind").bindTooltip({width:300});
8093
8094	//AXPopOverTooltip (bindTooltip) 방향설정 방식
8095	$("#tooltip4").bindTooltip({direction:"bottom", width:300}); //{direction:"[auto|top|bottom]"}
8096	$("#tooltip5").bindTooltip({direction:"top", width:300}); //{direction:"[auto|top|bottom]"}
8097	$("#tooltip6").bindTooltip({direction:"auto", width:300}); //{direction:"[auto|top|bottom]"}
8098 </script>
8099```
8100 */
8101axdom.fn.bindTooltip = function (config) {
8102    if (config == undefined) config = {};
8103    AXUtil.each(this, function () {
8104        var tooltipContent = axdom("#" + this.id + "_AX_tooltip").html();
8105        AXPopOver.bind({
8106            id: this.id + "_AX_tooltipobj",
8107            theme: (config.theme || "AXPopOverTooltip"), // 선택항목
8108            width: (config.width || ""), // 선택항목
8109            direction: (config.direction || "top"), // 선택항목
8110            body: tooltipContent
8111        });
8112
8113        axdom(this).bind((config.event || "mouseover"), function () {
8114            var pos = axdom(this).offset();
8115            var direction = (config.direction || "top");
8116            var posTop = pos.top;
8117            if (direction == "bottom") {
8118                posTop -= 3;
8119            } else {
8120                posTop += axdom(this).outerHeight() + 3;
8121            }
8122            AXPopOver.open({ id: this.id + "_AX_tooltipobj", sendObj: {} }
8122, { left: pos.left, top: posTop, handleHeight: (axdom(this).outerHeight().number() + 3) }); // event 직접 연결 방식
8123        });
8124    });
8125	return this;
8126};
8127/* ---------------------------------------------- AXContextMenu -- */
8128
8129/* -- AXMobileModal ---------------------------------------------- */
8130/**
8131 * @class AXMobileModal
8132 * @extends AXJ
8133 * @version v1.0
8134 * @author [email protected], axisj.com
8135 * @logs
8136 "2013-12-11 오후 5:48:28"
8137 "2014-04-14 : tom - modalOpen위치 scrollTop 적용"
8138 * @example
8139```js
8140 var myMobileModal = new AXMobileModal();
8141 // default config
8142 myMobileModal.config.theme = "AXMobileModal";
8143 myMobileModal.config.width = "auto";
8144 myMobileModal.config.height = "auto";
8145 myMobileModal.config.margin = "10px";
8146 myMobileModal.config.align = "center";
8147 myMobileModal.config.valign = "center";
8148```
8149 */
8150var AXMobileModal = Class.create(AXJ, {
8151    initialize: function (AXJ_super) {
8152        AXJ_super();
8153        this.config.theme = "AXMobileModal";
8154        this.config.width = "auto";
8155        this.config.height = "auto";
8156        this.config.margin = "10px";
8157        this.config.align = "center";
8158        this.config.valign = "center";
8159    },
8160/**
8161 * @method AXMobileModal.setConfig
8162 * @param {Object} configs
8163 * @description 모바일모달 개체 초기화
8164 * @example
8165```js
8166myMobileModal.setConfig({
8167	//theme, margin, align, valign
8168	width:300,
8169	height:300,
8170	head:{
8171		close:{
8172			onclick:function(){
8173
8174			}
8175		}
8176	},
8177	onclose: function(){
8178		trace("close bind");
8179	}
8180});
8181```
8182 */
8183    init: function () {
8184        var cfg = this.config;
8185
8186        if (!cfg.head) {
8187            cfg.head = {};
8188        }
8189    },
8190/**
8191 * @method AXMobileModal.open
8192 * @returns {Object} modalObject - 열린 모달의 오브젝트
8193 * @description 모바일 모달창을 열고 열린 모달의 엘리먼트 정보를 리턴합니다.
8194 * @example
8195```js
8196var obj = myMobileModal.open();
8197// 다음의 정보를 리턴합니다.
8198// obj: {
8199//    jQueryModal: 모달,
8200//    modalPanel: 모달의 패널,
8201//    modalHead: 모달패널의 헤드,
8202//    modalBody: 모달패널의 바디,
8203//    modalFoot: 모달패널의 풋
8204// }
8205
8206obj.modalHead.html("자유Head 설정테스트");
8207obj.modalBody.html("<div style='height:250px;background:#fff;text-align: center;line-height:30px;'>자유body 테스트</div>");
8208//obj.modalFoot.html("자유footer 테스트");
8209```
8210 */
8211    open: function (configs, onLoad) {
8212        var cfg = this.config;
8213        if (!configs) configs = {};
8214        var theme = (configs.theme || cfg.theme);
8215        if (cfg.addClass) {
8216            theme += " " + cfg.addClass;
8217        }
8218        this.modalId = "AXMobileModal" + AXUtil.timekey();
8219        var modalId = this.modalId;
8220        var clientWidth = (configs.clientWidth || AXUtil.clientWidth());
8221
8222        var po = [];
8223        po.push('<div id="', modalId, '" class="', theme, '" style="left:0px;top:0px;width:100%;height:100%;">');
8224        po.push('	<div  id="', modalId, '_AX_modal" class="AXMobileModalPanel" style="height:50px;width:50px;left:', (AXUtil.clientWidth() - 50) / 2, 'px;top:', (AXUtil.clientHeight() - 50) / 2,'px;">');
8225        po.push('		<div  id="', modalId, '_AX_head" class="mobileModalHead">');
8226        po.push('			<div class="modalTitle">' + (cfg.head.title || "") + '</div>');
8227        po.push('		</div>');
8228        if (cfg.head.close) {
8229            po.push('		<a ' + cfg.href + ' class="mobileModelClose">Close</a>');
8230        }
8231        po.push('		<div  id="', modalId, '_AX_body" class="mobileModalBody"></div>');
8232        po.push('		<div  id="', modalId, '_AX_foot" class="mobileModalFoot"></div>');
8233        po.push('	</div>');
8234        po.push('</div>');
8235        this.jQueryModal = axdom(po.join(''));
8236        axdom(document.body).append(this.jQueryModal);
8237
8238        this.modalPanel = this.jQueryModal.find(".AXMobileModalPanel");
8239        this.modalHead = this.modalPanel.find(".mobileModalHead");
8240        this.modalBody = this.modalPanel.find(".mobileModalBody");
8241        this.modalFoot = this.modalPanel.find(".mobileModalFoot");
8242
8243        this.openConfigs = configs;
8244        this.setSizeModal(this.openConfigs, onLoad);
8245        this.modalPanel.find(".mobileModelClose").bind("click", this.close.bind(this));
8246        this.jQueryModal.bind("click", this.modalClick.bind(this));
8247
8248        axdom(window).unbind("resize.AXMobileModal").bind("resize.AXMobileModal", this.reposition.bind(this));
8249
8250        this.opened = true;
8251
8252        return {
8253            jQueryModal: this.jQueryModal,
8254            modalPanel: this.modalPanel,
8255            modalHead: this.modalHead,
8256            modalBody: this.modalBody,
8257            modalFoot: this.modalFoot
8258        };
8259    },
8260    setSizeModal: function (configs, onLoad) {
8261        var cfg = this.config;
8262        var cssStyles = {};
8263        var clientWidth, width, height, left, top, margin, align, valign;
8264        var modalWidth, modalHeight;
8265        var clientWidth = this.jQueryModal.innerWidth();
8266        var clientHeight = AXUtil.clientHeight();
8267        var width = (configs.width || cfg.width);
8268        var height = (configs.height || cfg.height);
8269        var margin = (configs.margin || cfg.margin);
8270        var align = (configs.align || cfg.align);
8271        var valign = (configs.valign || cfg.valign);
8272
8273        this.openModalAttr = {
8274            width:width, height:height, margin:margin, align:align, valign:valign
8275        };
8276
8277        if (width == "auto") {
8278            if (margin.right(1) == "%") {
8279                modalWidth = clientWidth * (100 - margin.number() * 2) / 100;
8280            } else {
8281                modalWidth = clientWidth - margin.number() * 2;
8282            }
8283        } else {
8284            modalWidth = width;
8285        }
8286        left = (clientWidth - modalWidth) / 2;
8287
8288        if (height == "auto") {
8289            if (margin.right(1) == "%") {
8290                modalHeight = clientHeight * (100 - margin.number() * 2) / 100;
8291            } else {
8292                modalHeight = clientHeight - margin.number() * 2;
8293            }
8294        } else {
8295            modalHeight = height;
8296        }
8297        top = (clientHeight - modalHeight) / 2;
8298
8299        if (left < 0) left = margin;
8300	    if (top < -5) top = -5;
8301
8302        var cssStylesStart = {
8303            left: (axf.clientWidth() - (modalWidth*0.8)) / 2,
8304            top: (axf.clientHeight() - (modalHeight*0.8)) / 2,
8305            width: (modalWidth*0.8),
8306            height: (modalHeight*0.8)
8307        };
8308        //cssStylesStart.top += jQuery(window).scrollTop();
8309        this.modalPanel.css(cssStylesStart);
8310
8311        cssStyles.left = left;
8312        cssStyles.top = top;
8313        cssStyles.width = modalWidth;
8314        cssStyles.height = modalHeight;
8315        mask.open();
8316
8317        var returnObj = {
8318            jQueryModal: this.jQueryModal,
8319            modalPanel: this.modalPanel,
8320            modalHead: this.modalHead,
8321            modalBody: this.modalBody,
8322            modalFoot: this.modalFoot
8323        };
8324
8325        if(AXUtil.browser.name == "android"){
8326            //alert(AXUtil.browser.version);
8327            this.modalPanel.css(cssStyles);
8328            if(onLoad){
8329                onLoad.call(returnObj, returnObj);
8330            }
8331        }else{
8332            this.modalPanel.animate(cssStyles, 300, "expoOut", function () {
8333                if(onLoad){
8334                    onLoad.call(returnObj, returnObj);
8335                }
8336            });
8337        }
8338    },
8339    modalClick: function(event){
8340        var cfg = this.config;
8341        if(event.target.id == this.modalId){
8342            this.close();
8343        }
8344    },
8345
8346/**
8347 * @method AXMobileModal.close
8348 * @returns {AXMobileModal}
8349 * @description 모바일모달창을 닫습니다.
8350 * @example
8351```js
8352 myMobileModal.close();
8353```
8354 */
8355    close: function () {
8356        var cfg = this.config;
8357        mask.close();
8358
8359        var modalWidth, modalHeight;
8360        modalWidth = this.modalPanel.width();
8361        modalHeight = this.modalPanel.height();
8362
8363        var cssStylesStart = {
8364            left: (AXUtil.clientWidth() - (modalWidth*0.8)) / 2,
8365            top: (AXUtil.clientHeight() - (modalHeight*0.8)) / 2,
8366            width: (modalWidth*0.8),
8367            height: (modalHeight*0.8),
8368            opacity:0
8369        };
8370        var remove = this.remove.bind(this);
8371        this.modalPanel.animate(cssStylesStart, 300, "expoOut", function () {
8372            remove();
8373            if (cfg.onclose) {
8374                cfg.onclose();
8375            }
8376        });
8377        this.modalPanel.empty();
8378        //this.jQueryModal.fadeOut();
8379        //this.remove();
8380        /*
8381
8382         remove.delay(0.01);
8383         */
8384        this.opened = false;
8385        axdom(window).unbind("resize.AXMobileModal");
8386
8387		return this;
8388    },
8389    remove: function () {
8390        var cfg = this.config;
8391        this.jQueryModal.remove();
8392    },
8393    reposition: function(){
8394        var cfg = this.config;
8395
8396        var clientWidth = AXUtil.clientWidth();
8397        var clientHeight = AXUtil.clientHeight();
8398        this.jQueryModal.css({width:clientWidth, height:clientHeight});
8399
8400        var modalWidth, modalHeight, left, top;
8401        var width = this.openModalAttr.width;
8402        var height = this.openModalAttr.height;
8403        var margin = this.openModalAttr.margin;
8404        var align = this.openModalAttr.align;
8405        var valign = this.openModalAttr.valign;
8406        var cssStyles = {};
8407
8408        if (width == "auto") {
8409            if (margin.right(1) == "%") {
8410                modalWidth = clientWidth * (100 - margin.number() * 2) / 100;
8411            } else {
8412                modalWidth = clientWidth - margin.number() * 2;
8413            }
8414        } else {
8415            modalWidth = width;
8416        }
8417        left = (clientWidth - modalWidth) / 2;
8418
8419        if (height == "auto") {
8420            if (margin.right(1) == "%") {
8421                modalHeight = clientHeight * (100 - margin.number() * 2) / 100;
8422            } else {
8423                modalHeight = clientHeight - margin.number() * 2;
8424            }
8425        } else {
8426            modalHeight = height;
8427        }
8428        top = (clientHeight - modalHeight) / 2;
8429
8430        if (left < 0) left = margin;
8431        if (top < -5) top = -5;
8432
8433        cssStyles.left = left;
8434        cssStyles.top = top;
8435        cssStyles.width = modalWidth;
8436        cssStyles.height = modalHeight;
8437
8438        this.modalPanel.css(cssStyles);
8439    }
8440});
8441/* ---------------------------------------------- AXMobileModal -- */
8442
8443/* -- jQuery easing plugin ---------------------------------------------- */
8444axdom.extend(true, {
8445    easing: {
8446        backIn: function (p, n, f, d) { var c = f + d; var s = 1.70158; return c * (p /= 1) * p * ((s + 1) * p - s) + f; },
8447        backOut: function (p, n, f, d) { var c = f + d; var s = 1.70158; return c * ((p = p / 1 - 1) * p * ((s + 1) * p + s) + 1) + f; },
8448        backInOut: function (p, n, f, d) { var c = f + d; var s = 1.70158; if ((p /= 0.5) < 1) return c / 2 * (p * p * (((s *= (1.525)) + 1) * p - s)) + f; else return c / 2 * ((p -= 2) * p * (((s *= (1.525)) + 1) * p + s) + 2) + f; },
8449        bounceIn: function (p, n, f, d) { var c = f + d; var inv = this.bounceOut(1 - p, 1, 0, d); return c - inv + f; },
8450        bounceOut: function (p, n, f, d) { var c = f + d; if (p < (1 / 2.75)) return c * (7.5625 * p * p) + f; else if (p < (2 / 2.75)) return c * (7.5625 * (p -= (1.5 / 2.75)) * p + .75) + f; else if (p < (2.5 / 2.75)) return c * (7.5625 * (p -= (2.25 / 2.75)) * p + .9375) + f; else return c * (7.5625 * (p -= (2.625 / 2.75)) * p + .984375) + f; },
8451        circIn: function (p, n, f, d) { var c = f + d; return -c * (Math.sqrt(1 - (p /= 1) * p) - 1) + f; },
8452        circOut: function (p, n, f, d) { var c = f + d; return c * Math.sqrt(1 - (p = p / 1 - 1) * p) + f; },
8453        circInOut: function (p, n, f, d) { var c = f + d; if ((p /= 0.5) < 1) return -c / 2 * (Math.sqrt(1 - p * p) - 1) + f; else return c / 2 * (Math.sqrt(1 - (p -= 2) * p) + 1) + f; },
8454        cubicIn: function (p, n, f, d) { var c = f + d; return c * (p /= 1) * p * p + f; },
8455        cubicOut: function (p, n, f, d) { var c = f + d; return c * ((p = p / 1 - 1) * p * p + 1) + f; },
8456        cubicInOut: function (p, n, f, d) { var c = f + d; if ((p /= 0.5) < 1) return c / 2 * p * p * p + f; else return c / 2 * ((p -= 2) * p * p + 2) + f; },
8457        elasticIn: function (p, n, f, d) { var c = f + d; if (p == 0) return f; if (p == 1) return c; var peroid = 0.25; var s; var amplitude = c; if (amplitude < Math.abs(c)) { amplitude = c; s = peroid / 4; } else { s = peroid / (2 * Math.PI) * Math.asin(c / amplitude); } return -(amplitude * Math.pow(2, 10 * (p -= 1)) * Math.sin((p * 1 - s) * (2 * Math.PI) / peroid)) + f; },
8458        elasticOut: function (p, n, f, d) { var c = f + d; if (p == 0) return f; if (p == 1) return c; var peroid = 0.25; var s; var amplitude = c; if (amplitude < Math.abs(c)) { amplitude = c; s = peroid / 4; } else { s = peroid / (2 * Math.PI) * Math.asin(c / amplitude); } return -(amplitude * Math.pow(2, -10 * p) * Math.sin((p * 1 - s) * (2 * Math.PI) / peroid)) + c; },
8459        expoIn: function (p, n, f, d) { var c = f + d; return (p == 0) ? f : c * Math.pow(2, 10 * (p - 1)) + f - c * 0.001; },
8460        expoOut: function (p, n, f, d) { var c = f + d; return (p == 1) ? c : d * 1.001 * (-Math.pow(2, -10 * p) + 1) + f; },
8461        expoInOut: function (p, n, f, d) { var c = f + d; if (p == 0) return f; if (p == 1) return c; if ((p /= 0.5) < 1) return c / 2 * Math.pow(2, 10 * (p - 1)) + f - c * 0.0005; else return c / 2 * 1.0005 * (-Math.pow(2, -10 * --p) + 2) + f; },
8462        quadIn: function (p, n, f, d) { var c = f + d; return c * (p /= 1) * p + f; },
8463        quadOut: function (p, n, f, d) { var c = f + d; return -c * (p /= 1) * (p - 2) + f; },
8464        quadInOut: function (p, n, f, d) { var c = f + d; if ((p /= 0.5) < 1) return c / 2 * p * p + f; else return -c / 2 * ((--p) * (p - 2) - 1) + f; },
8465        quartIn: function (p, n, f, d) { var c = f + d; return c * (p /= 1) * p * p * p + f; },
8466        quartOut: function (p, n, f, d) { var c = f + d; return -c * ((p = p / 1 - 1) * p * p * p - 1) + f; },
8467        quartInOut: function (p, n, f, d) { var c = f + d; if ((p /= 0.5) < 1) return c / 2 * p * p * p * p + f; else return -c / 2 * ((p -= 2) * p * p * p - 2) + f; },
8468        quintIn: function (p, n, f, d) { var c = f + d; return c * (p /= 1) * p * p * p * p + f; },
8469        quintOut: function (p, n, f, d) { var c = f + d; return c * ((p = p / 1 - 1) * p * p * p * p + 1) + f; },
8470        quintInOut: function (p, n, f, d) { var c = f + d; if ((p /= 0.5) < 1) return c / 2 * p * p * p * p * p + f; else return c / 2 * ((p -= 2) * p * p * p * p + 2) + f; },
8471        sineIn: function (p, n, f, d) { var c = f + d; return -c * Math.cos(p * (Math.PI / 2)) + c + f; },
8472        sineOut: function (p, n, f, d) { var c = f + d; return c * Math.sin(p * (Math.PI / 2)) + f; },
8473        sineInOut: function (p, n, f, d) { var c = f + d; return -c / 2 * (Math.cos(Math.PI * p) - 1) + f; }
8474    }
8475});
8476/* ---------------------------------------------- jQuery easing plugin -- */
8477
8478// jQuery misc plugin
8479// 2014-08-08 tom : select option 이 없으면 엘리먼트를 찾지 않는 버그 픽스
8480var __r20 = /%20/g,
8481    __rbracket = /\[\]$/,
8482    __rCRLF = /\r?\n/g,
8483    __rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
8484    __rselectTextarea = /^(?:select|textarea)/i;
8485
8486// jquery event extend for mobile
8487var rkeyEvent = /^key/;
8488var rmouseEvent = /^(?:mouse|contextmenu)|click/;
8489axf.each(("touchstart touchmove touchend").split(" "), function (i, name) {
8490	axdom.fn[name] = function (data, fn) {
8491		if (fn == null) { fn = data; data = null; }
8492		return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name);
8493	};
8494	if (rkeyEvent.test(name)) { axdom.event.fixHooks[name] = axdom.event.keyHooks; }
8495	if (rmouseEvent.test(name)) { axdom.event.fixHooks[name] = axdom.event.mouseHooks; }
8496});
8497
8498/**
8499 * 설명
8500 * @member {type} AXJ.name
8501 */
8502/**
8503 * @method jQueryExtends.serializeObject
8504 * @returns {Array}
8505 * @description 엘리먼트 안에 폼아이템 요소들을 수집합니다. <en>Collect 'form item' inside target element</en>
8506 * @example
8507 ```js
8508 var myItems = $("#mytarget").serializeObject();
8509 ```
8510 */
8511axdom.fn.serializeObject = function () {
8512    var myArray = this.map(function () {
8513            return this.elements ? axdom.makeArray(this.elements) : this;
8514        })
8515        .filter(function () {
8516            return this.name && !this.disabled &&
8517                (this.checked || __rselectTextarea.test(this.nodeName) ||
8518                    __rinput.test(this.type));
8519        })
8520        .map(function (i, elem) {
8521            var val = axdom(this).val();
8522            var label = (axdom(elem).attr("title") || axdom(elem).attr("placeholder") || "");
8523
8524	        if(val == null){
8525		        if(this.nodeName.lcase() == "select") val = "";
8526	        }
8527
8528            return val == null ?
8529                null :
8530                axdom.isArray(val) ?
8531                    axdom.map(val, function (val, i) {
8532                        return { id: elem.id, name: elem.name, type: elem.type, value: val.replace(__rCRLF, "\r\n"), label: label };
8533                    }) :
8534                { id: elem.id, name: elem.name, type: elem.type, value: val.replace(__rCRLF, "\r\n"), label: label };
8535
8536        }).get();
8537    return myArray;
8538};
8539
8540/**
8541 * @method jQueryExtends.endFocus
8542 * @returns {jQueryObject}
8543 * @description input 엘리먼트 맨끝에 포커스되도록 합니다.
8544 * @example
8545 ```js
8546 $("#mytarget").endFocus();
8547 ```
8548 */
8549axdom.fn.endFocus = function () {
8550	var elem = this;
8551	var elemLen = elem.val().length;
8552	if (elemLen == 0) {
8553		elem.focus();
8554		return;
8555	}
8556	// For IE Only
8557	if (document.selection) {
8558		// Set focus
8559		elem.focus();
8560		elem.val(elem.val());
8561	}
8562	else if (document.selection == undefined || elem.selectionStart || elem.selectionStart == '0') {
8563		// Firefox/Chrome
8564		elem.focus().val(elem.val());
8565	} // if
8566	return this;
8567};
8568
8569/**
8570 * @method jQueryExtends.setCaret
8571 * @param {Number} [pos=valueLength] - 포커스 포지션 넘버
8572 * @returns {jQueryObject}
8573 * @description input 엘리먼트 특정위치에 커서를 위치시켜 줍니다.
8574 * @example
8575 ```js
8576 $("#mytarget").setCaret(2);
8577 ```
8578 */
8579axdom.fn.setCaret = function (pos) {
8580    var input = this[0];
8581    if(typeof pos == "undefined"){
8582        pos = input.value.length;
8583    }
8584    if (input.setSelectionRange) {
8585        input.focus();
8586        input.setSelectionRange(pos, pos);
8587    } else if (input.createTextRange) {
8588        var range = input.createTextRange();
8589        range.collapse(true);
8590        range.moveEnd('character', pos);
8591        range.moveStart('character', pos);
8592        range.select();
8593    } else if(input.selectionStart){
8594        input.focus();
8595        input.selectionStart = pos;
8596        input.selectionEnd = pos;
8597    }
8598	return this;
8599};
8600
8601/**
8602 * @method jQueryExtends.onwheel
8603 * @param {String} handler - 이벤트 키 네임
8604 * @param {Function} callBackFn - 이벤트 콜백 함수
8605 * @returns {jQueryObject}
8606 * @description 엘리먼트에 휠이벤트를 바인드 합니다. (단 엘리먼트에 id속성이 없는 경우 제대로 작동하지 않을 수 있습니다.)
8607 * @example
8608 ```
8609$("#mytarget").onwheel("mywheel", function(event){
8610	var delta = event.detail ? event.detail * (-20) : event.wheelDelta / 2;
8611	trace(delta);
8612});
8613 ```
8614 */
8615axdom.fn.onwheel = function(handler, callBackFn){
8616	axf.each(this,  function(){
8617		if(typeof axf._customerEvents == "undefined") axf._customerEvents = {};
8618		axf._customerEvents[this.id+"_AX_"+handler] = callBackFn;
8619		if (document.attachEvent) {
8620			this.attachEvent("on" + axf.mousewheelevt, axf._customerEvents[this.id+"_AX_"+handler]);
8621		} else if (document.addEventListener) {
8622			this.addEventListener(axf.mousewheelevt, axf._customerEvents[this.id+"_AX_"+handler], false);
8623		}
8624	});
8625	return this;
8626};
8627
8628/**
8629 * @method jQueryExtends.offwheel
8630 * @param {String} handler - 이벤트 키 네임
8631 * @returns {jQueryObject}
8632 * @description 엘리먼트에 휠이벤트를 언바인드 합니다. (단 엘리먼트에 id속성이 없는 경우 제대로 작동하지 않을 수 있습니다.)
8633 * @example
8634 ```
8635 $("#mytarget").offwheel("mywheel");
8636 ```
8637 */
8638axdom.fn.offwheel = function(handler){
8639	axf.each(this,  function(){
8640		if (document.attachEvent) {
8641			this.detachEvent("on" + axf.mousewheelevt, axf._customerEvents[this.id+"_AX_"+handler]);
8642		} else if (document.addEventListener) {
8643			this.removeEventListener(axf.mousewheelevt, axf._customerEvents[this.id+"_AX_"+handler], false);
8644		}
8645	});
8646	return this;
8647};
8648
8649/*
8650input type=text, textarea가 일부 브라우저에서 포커스 되지 않는 현상해결 해주는 구문
8651 */
8652axdom(document.body).ready(function () {
8653	axdom("input[type=text]").bind("mousedown", function () { this.focus(); });
8654	axdom("textarea").bind("mousedown", function () { this.focus(); });
8655});

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.