공통 js 리팩토링 진행

dev
박성영 3 months ago
parent b2ddad311c
commit 2fcac9ab24

@ -1,3 +1,8 @@
// =============================================================================
// 2. DOM 초기화 및 마스크 설정 (시스템 초기화 관련)
// =============================================================================
// 날짜피커 한국어 설정
$.fn.datepicker.dates['kr'] = {
days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
daysShort: ["일", "월", "화", "수", "목", "금", "토"],
@ -11,6 +16,7 @@ $.fn.datepicker.dates['kr'] = {
weekStart: 0
};
// DOM 준비 완료 시 초기화 함수들
$(document).ready(function () {
$("body").on("focus", ".datepicker", function () {
@ -96,7 +102,6 @@ $(document).ready(function () {
});
});
// 중요로직: Strct_Idx_Cd 전용 마스크 - 숫자 3자리
$("body").on("focus", ".strctIdxCdMask", function () {
$(this).inputmask({
@ -227,244 +232,9 @@ $(document).ready(function () {
});
/**
* Checks if value is empty. Deep-checks arrays and objects Note: isEmpty([]) ==
* true, isEmpty({}) == true, isEmpty([{0:false},"",0]) == true, isEmpty({0:1}) ==
* false
*
* @param value
* @returns {boolean}
*/
function isEmpty(value) {
if (value === null || value === undefined) {
return true;
}
if (typeof value === 'string' && value.trim() === '') {
return true;
}
if (Array.isArray(value) && value.length === 0) {
return true;
}
if (typeof value === 'object' && Object.keys(value).length === 0) {
return true;
}
return false;
/*
기존소스 주석. 0 true 이닌 false 처리
var isEmptyObject = function(a) {
if(typeof a.length === 'undefined') { // it's an Object, not an Array
var hasNonempty = Object.keys(a).some(function nonEmpty(element) {
return !isEmpty(a[element]);
});
return hasNonempty ? false : isEmptyObject(Object.keys(a));
}
return !a.some(function nonEmpty(element) { // check if array is really
// not empty as JS thinks
return !isEmpty(element); // at least one element should be
// non-empty
});
};
return(value == false || typeof value === 'undefined' || value == null || (typeof value === 'object' && isEmptyObject(value)));
*/
}
/**
* null 이나 빈값을 기본값으로 변경
*
* @param str
* 입력값
* @param defaultVal
* 기본값(옵션)
* @returns {String} 체크 결과값
*/
function nvl(str, defaultVal) {
var defaultValue = "";
if(typeof defaultVal != 'undefined') {
defaultValue = defaultVal;
}
if(typeof str == "undefined" || str == null || str == '' || str == "undefined") {
return defaultValue;
}
return str;
}
/**
* 길이체크
*
* @param str
* @returns {Number}
*/
function checkLength(str) {
var stringLength = str.length;
var stringByteLength = 0;
for(var i = 0; i < stringLength; i++) {
if(escape(str.charAt(i)).length >= 4) {
stringByteLength += 3;
} else if(escape(str.charAt(i)) == "%A7") {
stringByteLength += 3;
} else {
if(escape(str.charAt(i)) != "%0D") {
stringByteLength++;
}
}
}
return stringByteLength;
}
/**
* Left 빈자리 만큼 str 붙인다.
* @param src : Right에 붙을 원본 데이터
* @param len : str붙힐 데이터 길이
* @param str : 대상 데이터
* @returns : str과 src가 붙은 데이터
* @example : lpad("123123", 10, " ");
*/
function lpad(src, len, str) {
var retStr = "";
var padCnt = Number(len) - String(src).length;
for(var i=0;i<padCnt;i++) {
retStr += String(str);
}
return retStr+src;
}
/**
* Right 빈자리 만큼 str 붙인다.
* @param src : Left에 붙을 원본 데이터
* @param len : str붙힐 데이터 길이
* @param str : 대상 데이터
* @returns : str과 src가 붙은 데이터
* @example : rpad("123123", 10, " ");
*/
function rpad(src, len, str) {
var retStr = "";
var padCnt = Number(len) - String(src).length;
for(var i=0;i<padCnt;i++) {
retStr += String(str);
}
return src+retStr;
}
/**
* 절상, 절하, 반올림 처리
* @param strMode - 수식
* @param nCalcVal - 처리할 (소수점 이하 데이터 포함)
* @param nDigit - 연산 기준 자릿수(오라클의 ROUND함수 자릿수 기준)
* -2:십단위, -1:원단위, 0:소수점 1자리
* 1:소수점 2자리, 2:소수점 3자리, 3:소수점 4자리, 4:소수점 5자리 처리
* @return String nCalcVal
*/
function fnCalcMath(strMode, nCalcVal, nDigit) {
if(strMode == "CEIL") { //절상
if(nDigit < 0) {
nDigit = -(nDigit);
nCalcVal = Math.ceil(nCalcVal / Math.pow(10, nDigit)) * Math.pow(10, nDigit);
} else {
nCalcVal = Math.ceil(nCalcVal * Math.pow(10, nDigit)) / Math.pow(10, nDigit);
}
} else if(strMode == "FLOOR") { //절하
if(nDigit < 0) {
nDigit = -(nDigit);
nCalcVal = Math.floor(nCalcVal / Math.pow(10, nDigit)) * Math.pow(10, nDigit);
} else {
nCalcVal = Math.floor(nCalcVal * Math.pow(10, nDigit)) / Math.pow(10, nDigit);
}
} else { //반올림
if(nDigit < 0) {
nDigit = -(nDigit);
nCalcVal = Math.round(nCalcVal / Math.pow(10, nDigit)) * Math.pow(10, nDigit);
} else {
nCalcVal = Math.round(nCalcVal * Math.pow(10, nDigit)) / Math.pow(10, nDigit);
}
}
return nCalcVal;
}
/***********************************************************************************
* : isNull
* : null 체크 함수
* : value
* : boolean
**********************************************************************************/
var isNull = function(value) {
if (new String(value).valueOf() == "undefined") return true;
if (value == null) return true;
value = trimAll(value);
value = new String(value);
if (value == null) return true;
if (value.toString().length == 0) return true;
return false;
};
/***********************************************************************************
* : utils.trimAll
* : 문자열 전체의 공백제거 함수
* : value
* : string
**********************************************************************************/
var trimAll = function(value) {
if (value == null) return "";
if (new String(value).valueOf() == "undefined") return "";
var rtnValue = "";
value = new String(value);
if (value != null) {
for(var i=0; i<value.length; i++) {
if (value.charAt(i) != " ") {
rtnValue = rtnValue + value.charAt(i);
}
}
} else {
return -1;
}
return rtnValue;
};
var downloadAjax = function(data, jqXhr) {
if (!data) {
alert("다운로드 파일이 없습니다.");
return;
}
try {
var blob = new Blob([data], { type: jqXhr.getResponseHeader('content-type') });
var fileName = getFileName(jqXhr.getResponseHeader('content-disposition'));
fileName = decodeURI(fileName);
if (window.navigator.msSaveOrOpenBlob) { // IE 10+
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else { // not IE
var link = document.createElement('a');
var url = window.URL.createObjectURL(blob);
link.href = url;
link.target = '_self';
if (fileName) link.download = fileName;
document.body.append(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
}
} catch (e) {
alert("다운로드 중 에러입니다.");
console.error(e)
}
}
/**
* URL 파라미터 관리 유틸리티
* 검색 조건 유지 파라미터 관리를 위한 함수 모음
*/
// =============================================================================
// 3. URL 파라미터 관리 함수들 (검색 조건 유지 및 파라미터 관리)
// =============================================================================
/**
* URL의 쿼리 파라미터를 객체로 변환
@ -502,6 +272,23 @@ var getUrlParams = function(search) {
return params;
};
/**
* URL에서 파라미터 가져오기
*
* @param {string} paramName - 가져올 파라미터 이름
* @param {string} defaultValue - 파라미터가 없을 경우 기본값
* @param {string} url - 대상 URL (기본값: 현재 페이지 URL)
* @returns {string} 파라미터 또는 기본값
*/
var getUrlParam = function(paramName, defaultValue, url) {
// URL이 없으면 현재 페이지 URL 사용
var targetUrl = url || window.location.href;
var params = getUrlParams(targetUrl.split('?')[1] ? '?' + targetUrl.split('?')[1] : '');
// 파라미터 값이 있으면 반환, 없으면 기본값 반환
return params[paramName] !== undefined ? params[paramName] : (defaultValue || null);
};
/**
* URL에 파라미터 추가
*
@ -579,23 +366,6 @@ var removeUrlParam = function(paramName, url) {
return baseUrl + (queryString ? '?' + queryString : '');
};
/**
* URL에서 파라미터 가져오기
*
* @param {string} paramName - 가져올 파라미터 이름
* @param {string} defaultValue - 파라미터가 없을 경우 기본값
* @param {string} url - 대상 URL (기본값: 현재 페이지 URL)
* @returns {string} 파라미터 또는 기본값
*/
var getUrlParam = function(paramName, defaultValue, url) {
// URL이 없으면 현재 페이지 URL 사용
var targetUrl = url || window.location.href;
var params = getUrlParams(targetUrl.split('?')[1] ? '?' + targetUrl.split('?')[1] : '');
// 파라미터 값이 있으면 반환, 없으면 기본값 반환
return params[paramName] !== undefined ? params[paramName] : (defaultValue || null);
};
/**
* URL에서 파라미터 변경
*
@ -761,6 +531,10 @@ var buildContextUrl = function(url) {
return result;
};
// =============================================================================
// 4. 공통 코드 및 선택박스 관리
// =============================================================================
/**
* 공통코드를 조회하여 select box에 option을 추가하는 함수
* 중요로직: 코드 그룹 ID를 기준으로 해당 코드들을 조회하여 select box를 동적으로 생성
@ -890,40 +664,10 @@ function commonCodeSelectAjax(cdGroupId, selectId, firstOptionText, selectedValu
}
});
}
/**
* 자식 팝업창들을 모두 닫고 현재 창을 닫는 공통 함수
*
* @param {Array} childPopups - 자식 팝업창 참조 배열
* @returns {Array} 초기화된 배열
*/
function closeChildPopupsAndSelf(childPopups) {
// 자식 팝업창들이 배열이 아닌 경우 빈 배열로 초기화
if (!Array.isArray(childPopups)) {
childPopups = [];
}
// 열려있는 자식 팝업창들을 먼저 닫기
for (var i = 0; i < childPopups.length; i++) {
try {
if (childPopups[i] && !childPopups[i].closed) {
childPopups[i].close();
}
} catch (e) {
// 팝업창 접근 오류 무시 (이미 닫혔거나 접근 권한 없음)
console.warn('팝업창 닫기 중 오류 발생:', e.message);
}
}
// 자식 팝업 배열 초기화
childPopups.length = 0;
// 자신의 창 닫기
window.close();
// 초기화된 배열 반환
return childPopups;
}
// =============================================================================
// 5. UI 컴포넌트 (드롭다운)
// =============================================================================
/**
* 전역 드롭다운 인스턴스 관리
@ -1434,6 +1178,10 @@ XitDropdown.prototype = {
}
};
// =============================================================================
// 6. 파일 다운로드 및 기타 유틸리티 함수들
// =============================================================================
/**
* 팝업 열기 공통함수
* 중요로직: 팝업창을 화면 중앙에 위치시켜 열기, 위치 조정 가능
@ -1468,3 +1216,273 @@ function openPopup(url, width, height, windowName, leftOffset, topOffset) {
return window.open(url, windowName, popupOptions);
}
/**
* 자식 팝업창들을 모두 닫고 현재 창을 닫는 공통 함수
*
* @param {Array} childPopups - 자식 팝업창 참조 배열
* @returns {Array} 초기화된 배열
*/
function closeChildPopupsAndSelf(childPopups) {
// 자식 팝업창들이 배열이 아닌 경우 빈 배열로 초기화
if (!Array.isArray(childPopups)) {
childPopups = [];
}
// 열려있는 자식 팝업창들을 먼저 닫기
for (var i = 0; i < childPopups.length; i++) {
try {
if (childPopups[i] && !childPopups[i].closed) {
childPopups[i].close();
}
} catch (e) {
// 팝업창 접근 오류 무시 (이미 닫혔거나 접근 권한 없음)
console.warn('팝업창 닫기 중 오류 발생:', e.message);
}
}
// 자식 팝업 배열 초기화
childPopups.length = 0;
// 자신의 창 닫기
window.close();
// 초기화된 배열 반환
return childPopups;
}
var downloadAjax = function(data, jqXhr) {
if (!data) {
alert("다운로드 파일이 없습니다.");
return;
}
try {
var blob = new Blob([data], { type: jqXhr.getResponseHeader('content-type') });
var fileName = getFileName(jqXhr.getResponseHeader('content-disposition'));
fileName = decodeURI(fileName);
if (window.navigator.msSaveOrOpenBlob) { // IE 10+
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else { // not IE
var link = document.createElement('a');
var url = window.URL.createObjectURL(blob);
link.href = url;
link.target = '_self';
if (fileName) link.download = fileName;
document.body.append(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
}
} catch (e) {
alert("다운로드 중 에러입니다.");
console.error(e)
}
}
// =============================================================================
// 1. 핵심 유틸리티 함수들 (가장 중요 - 전체적으로 사용되는 기본 함수들)
// =============================================================================
/**
* Checks if value is empty. Deep-checks arrays and objects Note: isEmpty([]) ==
* true, isEmpty({}) == true, isEmpty([{0:false},"",0]) == true, isEmpty({0:1}) ==
* false
*
* @param value
* @returns {boolean}
*/
function isEmpty(value) {
if (value === null || value === undefined) {
return true;
}
if (typeof value === 'string' && value.trim() === '') {
return true;
}
if (Array.isArray(value) && value.length === 0) {
return true;
}
if (typeof value === 'object' && Object.keys(value).length === 0) {
return true;
}
return false;
/*
기존소스 주석. 0 true 이닌 false 처리
var isEmptyObject = function(a) {
if(typeof a.length === 'undefined') { // it's an Object, not an Array
var hasNonempty = Object.keys(a).some(function nonEmpty(element) {
return !isEmpty(a[element]);
});
return hasNonempty ? false : isEmptyObject(Object.keys(a));
}
return !a.some(function nonEmpty(element) { // check if array is really
// not empty as JS thinks
return !isEmpty(element); // at least one element should be
// non-empty
});
};
return(value == false || typeof value === 'undefined' || value == null || (typeof value === 'object' && isEmptyObject(value)));
*/
}
/**
* null 이나 빈값을 기본값으로 변경
*
* @param str
* 입력값
* @param defaultVal
* 기본값(옵션)
* @returns {String} 체크 결과값
*/
function nvl(str, defaultVal) {
var defaultValue = "";
if(typeof defaultVal != 'undefined') {
defaultValue = defaultVal;
}
if(typeof str == "undefined" || str == null || str == '' || str == "undefined") {
return defaultValue;
}
return str;
}
/***********************************************************************************
* : isNull
* : null 체크 함수
* : value
* : boolean
**********************************************************************************/
var isNull = function(value) {
if (new String(value).valueOf() == "undefined") return true;
if (value == null) return true;
value = trimAll(value);
value = new String(value);
if (value == null) return true;
if (value.toString().length == 0) return true;
return false;
};
/***********************************************************************************
* : utils.trimAll
* : 문자열 전체의 공백제거 함수
* : value
* : string
**********************************************************************************/
var trimAll = function(value) {
if (value == null) return "";
if (new String(value).valueOf() == "undefined") return "";
var rtnValue = "";
value = new String(value);
if (value != null) {
for(var i=0; i<value.length; i++) {
if (value.charAt(i) != " ") {
rtnValue = rtnValue + value.charAt(i);
}
}
} else {
return -1;
}
return rtnValue;
};
/**
* 길이체크
*
* @param str
* @returns {Number}
*/
function checkLength(str) {
var stringLength = str.length;
var stringByteLength = 0;
for(var i = 0; i < stringLength; i++) {
if(escape(str.charAt(i)).length >= 4) {
stringByteLength += 3;
} else if(escape(str.charAt(i)) == "%A7") {
stringByteLength += 3;
} else {
if(escape(str.charAt(i)) != "%0D") {
stringByteLength++;
}
}
}
return stringByteLength;
}
/**
* Left 빈자리 만큼 str 붙인다.
* @param src : Right에 붙을 원본 데이터
* @param len : str붙힐 데이터 길이
* @param str : 대상 데이터
* @returns : str과 src가 붙은 데이터
* @example : lpad("123123", 10, " ");
*/
function lpad(src, len, str) {
var retStr = "";
var padCnt = Number(len) - String(src).length;
for(var i=0;i<padCnt;i++) {
retStr += String(str);
}
return retStr+src;
}
/**
* Right 빈자리 만큼 str 붙인다.
* @param src : Left에 붙을 원본 데이터
* @param len : str붙힐 데이터 길이
* @param str : 대상 데이터
* @returns : str과 src가 붙은 데이터
* @example : rpad("123123", 10, " ");
*/
function rpad(src, len, str) {
var retStr = "";
var padCnt = Number(len) - String(src).length;
for(var i=0;i<padCnt;i++) {
retStr += String(str);
}
return src+retStr;
}
/**
* 절상, 절하, 반올림 처리
* @param strMode - 수식
* @param nCalcVal - 처리할 (소수점 이하 데이터 포함)
* @param nDigit - 연산 기준 자릿수(오라클의 ROUND함수 자릿수 기준)
* -2:십단위, -1:원단위, 0:소수점 1자리
* 1:소수점 2자리, 2:소수점 3자리, 3:소수점 4자리, 4:소수점 5자리 처리
* @return String nCalcVal
*/
function fnCalcMath(strMode, nCalcVal, nDigit) {
if(strMode == "CEIL") { //절상
if(nDigit < 0) {
nDigit = -(nDigit);
nCalcVal = Math.ceil(nCalcVal / Math.pow(10, nDigit)) * Math.pow(10, nDigit);
} else {
nCalcVal = Math.ceil(nCalcVal * Math.pow(10, nDigit)) / Math.pow(10, nDigit);
}
} else if(strMode == "FLOOR") { //절하
if(nDigit < 0) {
nDigit = -(nDigit);
nCalcVal = Math.floor(nCalcVal / Math.pow(10, nDigit)) * Math.pow(10, nDigit);
} else {
nCalcVal = Math.floor(nCalcVal * Math.pow(10, nDigit)) / Math.pow(10, nDigit);
}
} else { //반올림
if(nDigit < 0) {
nDigit = -(nDigit);
nCalcVal = Math.round(nCalcVal / Math.pow(10, nDigit)) * Math.pow(10, nDigit);
} else {
nCalcVal = Math.round(nCalcVal * Math.pow(10, nDigit)) / Math.pow(10, nDigit);
}
}
return nCalcVal;
}

@ -1,3 +1,12 @@
/* =========================================================================
* XIT Common JavaScript Library
* 중요도 순서: 1.환경설정 2.세션/보안 3.Ajax통신 4.공통유틸 5.UI컴포넌트
* ========================================================================= */
/* =============================================================================
* 1. ENVIRONMENT CONFIGURATION (최우선 - 시스템 기본 설정)
* ============================================================================= */
/* 컨택스트 패스 설정 로드 */
// 기본값 설정 (설정 로드 실패 시 사용)
var contextPath = '';
@ -41,6 +50,218 @@ var loginUrl = '/login/login.do';
document.head.appendChild(script);
})();
/* =============================================================================
* 2. SESSION & SECURITY MANAGEMENT (세션 보안 관리)
* ============================================================================= */
/**
* 세션 만료 처리 함수 - 모든 팝업을 닫고 로그인 페이지로 이동
* 중요로직: 팝업 환경에서 세션 만료 현재 팝업이 아닌 최상위 창에서 로그인 페이지로 이동
*/
function handleSessionExpired() {
try {
console.log('[세션 만료] 처리 시작');
// 중요로직: 현재 창이 팝업인지 확인
var isPopup = !!(window.opener && !window.opener.closed);
console.log('[세션 만료] 현재 창 팝업 여부:', isPopup);
if (isPopup) {
// 팝업인 경우: 최상위 부모창 찾기
var topWindow = window;
var windowChain = [];
var currentWindow = window;
// 최상위 창까지 탐색
while (currentWindow && currentWindow.opener && !currentWindow.opener.closed) {
windowChain.push(currentWindow);
currentWindow = currentWindow.opener;
topWindow = currentWindow;
// 무한루프 방지 (최대 10단계)
if (windowChain.length > 10) {
console.warn('[세션 만료] 너무 많은 팝업 체인, 탐색 중단');
break;
}
}
console.log('[세션 만료] 팝업 체인 길이:', windowChain.length);
console.log('[세션 만료] 최상위 창 찾음:', !!topWindow);
// 메시지 표시 (현재 팝업에서)
alert("세션이 종료되었습니다. 다시 로그인해주세요.");
// 최상위 창을 로그인 페이지로 이동
if (topWindow && !topWindow.closed) {
try {
topWindow.location.href = (contextPath || '') + loginUrl;
console.log('[세션 만료] 최상위 창 리다이렉트 성공');
} catch (redirectError) {
console.warn('[세션 만료] 최상위 창 리다이렉트 실패:', redirectError);
// 리다이렉트 실패 시 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
}
} else {
// 최상위 창이 닫혀있는 경우 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
console.log('[세션 만료] 현재 창에서 리다이렉트');
}
// 모든 팝업창 닫기 (약간의 지연 후)
setTimeout(function() {
try {
// 하위 팝업부터 상위 팝업 순서로 닫기
for (var i = 0; i < windowChain.length; i++) {
try {
var popupWindow = windowChain[i];
if (popupWindow && !popupWindow.closed) {
popupWindow.close();
console.log('[세션 만료] 팝업창 닫기 성공:', i + 1);
}
} catch (closeError) {
console.warn('[세션 만료] 팝업창 닫기 실패:', closeError);
}
}
console.log('[세션 만료] 모든 팝업창 닫기 완료');
} catch (e) {
console.warn('[세션 만료] 팝업창 일괄 닫기 실패:', e);
}
}, 300); // 리다이렉트 후 약간의 지연
} else {
// 일반 페이지인 경우 기존 로직 사용
console.log('[세션 만료] 일반 페이지에서 처리');
redirectToLoginWithCloseAllPopups("세션이 종료되었습니다. 다시 로그인해주세요.");
}
} catch (e) {
console.error('[세션 만료] 전체 처리 중 오류:', e);
// 모든 처리가 실패한 경우 기본 처리
try {
alert("세션이 종료되었습니다. 다시 로그인해주세요.");
location.href = (contextPath || '') + loginUrl;
} catch (finalError) {
console.error('[세션 만료] 최종 처리도 실패:', finalError);
location.reload();
}
}
}
/**
* 모든 팝업을 닫고 메인페이지를 로그인 페이지로 이동시키는 함수
* 중요로직: 다중 팝업 구조에서 안전하게 모든 팝업을 닫고 최상위 창만 로그인 페이지로 이동
* @param {string} message - 사용자에게 표시할 메시지 (선택사항)
* @param {boolean} showAlert - alert 표시 여부 (기본값: true)
*/
function redirectToLoginWithCloseAllPopups(message, showAlert) {
try {
// 기본값 설정
if (showAlert === undefined) showAlert = true;
if (!message) message = "로그인 페이지로 이동합니다.";
// 메시지 표시
if (showAlert) {
alert(message);
}
// 중요로직: 최상위 부모창 찾기 (다중 팝업 처리)
var topWindow = window;
var currentWindow = window;
// 현재 창부터 최상위까지의 모든 창 정보 수집
var windowChain = [];
while (currentWindow) {
windowChain.push({
window: currentWindow,
isPopup: !!(currentWindow.opener && !currentWindow.opener.closed)
});
if (currentWindow.opener && !currentWindow.opener.closed) {
currentWindow = currentWindow.opener;
topWindow = currentWindow;
} else {
break;
}
}
console.log('[로그인 리다이렉트] 창 체인 정보:', windowChain.length + '개의 창 감지');
// 최상위 부모창을 로그인 페이지로 이동
if (topWindow && !topWindow.closed) {
try {
topWindow.location.href = (contextPath || '') + loginUrl;
console.log('[로그인 리다이렉트] 최상위 창 리다이렉트 성공');
} catch (redirectError) {
console.warn('[로그인 리다이렉트] 최상위 창 리다이렉트 실패:', redirectError);
// 리다이렉트 실패 시 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
}
} else {
// 최상위 창이 닫혀있는 경우 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
console.log('[로그인 리다이렉트] 현재 창에서 리다이렉트');
}
// 중요로직: 메인창 외에 모든 팝업창 종료
setTimeout(function() {
try {
var popupsToClose = windowChain.filter(function(item) {
return item.isPopup;
});
console.log('[로그인 리다이렉트] 닫을 팝업 수:', popupsToClose.length);
// 수집된 모든 팝업창을 닫기 (하위창부터 상위창 순서)
for (var i = 0; i < popupsToClose.length; i++) {
try {
var popupWindow = popupsToClose[i].window;
if (popupWindow && !popupWindow.closed) {
popupWindow.close();
console.log('[로그인 리다이렉트] 팝업창 닫기 성공:', i + 1);
}
} catch (closeError) {
console.warn('[로그인 리다이렉트] 팝업창 닫기 실패:', closeError);
}
}
console.log('[로그인 리다이렉트] 모든 팝업창 닫기 완료');
} catch (e) {
console.warn('[로그인 리다이렉트] 팝업창 일괄 닫기 실패:', e);
// 기본 방식으로 현재 창 닫기 시도
if (window.opener && !window.opener.closed) {
try {
window.close();
} catch (fallbackError) {
console.warn('[로그인 리다이렉트] 기본 방식 팝업창 닫기도 실패:', fallbackError);
}
}
}
}, 200); // 리다이렉트 후 약간의 지연을 두어 안정성 확보
} catch (e) {
console.error("[로그인 리다이렉트] 전체 처리 중 오류:", e);
// 모든 처리가 실패한 경우 현재 창에서 로그인 페이지로 이동
try {
location.href = (contextPath || '') + loginUrl;
} catch (finalError) {
console.error("[로그인 리다이렉트] 최종 리다이렉트도 실패:", finalError);
// 최후의 수단으로 새로고침
location.reload();
}
}
}
/**
* 로그아웃 함수 - 모든 팝업을 닫고 로그인 페이지로 이동
*/
function logout() {
redirectToLoginWithCloseAllPopups("로그아웃 되었습니다.");
}
/* =============================================================================
* 3. AJAX COMMUNICATION (Ajax 통신 관리)
* ============================================================================= */
/* jQuery Ajax 설정 */
$.ajaxSetup({
type:"POST",
@ -76,6 +297,9 @@ $(document).ajaxError( function( event, jqxhr, settings, exception ){
});
/* Ajax Progress Block UI 설정 */
// Ajax 활성 요청 카운터 (동시 Ajax 요청 처리를 위함)
var activeAjaxCount = 0;
// Progress Block UI 초기화
$(document).ready(function() {
// Progress Block UI 생성
@ -87,9 +311,6 @@ $(document).ready(function() {
console.log('[Ajax Block UI] Ajax 카운터 초기화:', activeAjaxCount);
});
// Ajax 활성 요청 카운터 (동시 Ajax 요청 처리를 위함)
var activeAjaxCount = 0;
// Ajax 시작 시 Progress Block UI 표시
$(document).ajaxSend(function(event, jqXHR, ajaxOptions) {
console.log('[Ajax Block UI] Ajax 시작:', ajaxOptions.url);
@ -178,45 +399,11 @@ function createProgressBlockUI() {
}
}
/* =============================================================================
* 4. COMMON UTILITIES (공통 유틸리티 함수들)
* ============================================================================= */
$(document).ready(function () {
$('.pop-x-btn, .modalclose').click(function() {
var tmp = $(this).parents().parents().parents()
if (tmp.attr('class') == 'modalz act') {
tmp.removeClass('act');
} else {
//tmp.removeClass('act');
}
});
});
/**
* 모달 닫기 이벤트를 설정하는 함수
* 모달 닫기 버튼 클릭 모달 외부 클릭 모달을 닫는 이벤트를 설정합니다.
* @param {string} modalId - 모달 요소의 ID (기본값: 'modal')
* @param {string} closeBtnSelector - 닫기 버튼의 선택자 (기본값: '.pop-x-btn, .modalclose')
*/
function initModalClose(modalId) {
// 기본값 설정
modalId = modalId || 'modal';
// '#' 접두사가 없는 경우 추가
if (!modalId.startsWith('#')) {
modalId = '#' + modalId;
}
// 모달 외부 클릭 시 닫기 (dim 영역 클릭 시)
$(modalId + ' .dim').on('click', function() {
$(modalId).removeClass('act');
});
// ESC 키 입력 시 모달 닫기
$(document).on('keydown', function(e) {
if (e.keyCode === 27 && $(modalId).hasClass('act')) { // ESC key
$(modalId).removeClass('act');
}
});
}
/* 4.1 VALIDATION UTILITIES (검증 관련 함수들) */
/**
* HTML 엔티티를 원래 문자로 변환하는 함수
@ -346,6 +533,8 @@ function unescapeHtml(input) {
}
}
/* 4.2 COLOR UTILITIES (색상 관련 함수들) */
/**
* selectbox option에 data-color가 있을 자동으로 색상을 적용하는 함수
* @param {string|jQuery} selector - selectbox 선택자 또는 jQuery 객체
@ -398,210 +587,53 @@ function makeColorTransparent(color, opacity) {
return color;
}
/**
* 모든 팝업을 닫고 메인페이지를 로그인 페이지로 이동시키는 함수
* 중요로직: 다중 팝업 구조에서 안전하게 모든 팝업을 닫고 최상위 창만 로그인 페이지로 이동
* @param {string} message - 사용자에게 표시할 메시지 (선택사항)
* @param {boolean} showAlert - alert 표시 여부 (기본값: true)
*/
function redirectToLoginWithCloseAllPopups(message, showAlert) {
try {
// 기본값 설정
if (showAlert === undefined) showAlert = true;
if (!message) message = "로그인 페이지로 이동합니다.";
/* =============================================================================
* 5. UI COMPONENTS (UI 컴포넌트들)
* ============================================================================= */
// 메시지 표시
if (showAlert) {
alert(message);
}
// 중요로직: 최상위 부모창 찾기 (다중 팝업 처리)
var topWindow = window;
var currentWindow = window;
/* 5.1 MODAL UTILITIES (모달 관련 함수들) */
// 현재 창부터 최상위까지의 모든 창 정보 수집
var windowChain = [];
while (currentWindow) {
windowChain.push({
window: currentWindow,
isPopup: !!(currentWindow.opener && !currentWindow.opener.closed)
});
if (currentWindow.opener && !currentWindow.opener.closed) {
currentWindow = currentWindow.opener;
topWindow = currentWindow;
} else {
break;
}
}
console.log('[로그인 리다이렉트] 창 체인 정보:', windowChain.length + '개의 창 감지');
// 최상위 부모창을 로그인 페이지로 이동
if (topWindow && !topWindow.closed) {
try {
topWindow.location.href = (contextPath || '') + loginUrl;
console.log('[로그인 리다이렉트] 최상위 창 리다이렉트 성공');
} catch (redirectError) {
console.warn('[로그인 리다이렉트] 최상위 창 리다이렉트 실패:', redirectError);
// 리다이렉트 실패 시 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
}
$(document).ready(function () {
$('.pop-x-btn, .modalclose').click(function() {
var tmp = $(this).parents().parents().parents()
if (tmp.attr('class') == 'modalz act') {
tmp.removeClass('act');
} else {
// 최상위 창이 닫혀있는 경우 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
console.log('[로그인 리다이렉트] 현재 창에서 리다이렉트');
}
// 중요로직: 메인창 외에 모든 팝업창 종료
setTimeout(function() {
try {
var popupsToClose = windowChain.filter(function(item) {
return item.isPopup;
});
console.log('[로그인 리다이렉트] 닫을 팝업 수:', popupsToClose.length);
// 수집된 모든 팝업창을 닫기 (하위창부터 상위창 순서)
for (var i = 0; i < popupsToClose.length; i++) {
try {
var popupWindow = popupsToClose[i].window;
if (popupWindow && !popupWindow.closed) {
popupWindow.close();
console.log('[로그인 리다이렉트] 팝업창 닫기 성공:', i + 1);
}
} catch (closeError) {
console.warn('[로그인 리다이렉트] 팝업창 닫기 실패:', closeError);
}
}
console.log('[로그인 리다이렉트] 모든 팝업창 닫기 완료');
} catch (e) {
console.warn('[로그인 리다이렉트] 팝업창 일괄 닫기 실패:', e);
// 기본 방식으로 현재 창 닫기 시도
if (window.opener && !window.opener.closed) {
try {
window.close();
} catch (fallbackError) {
console.warn('[로그인 리다이렉트] 기본 방식 팝업창 닫기도 실패:', fallbackError);
}
}
}
}, 200); // 리다이렉트 후 약간의 지연을 두어 안정성 확보
} catch (e) {
console.error("[로그인 리다이렉트] 전체 처리 중 오류:", e);
// 모든 처리가 실패한 경우 현재 창에서 로그인 페이지로 이동
try {
location.href = (contextPath || '') + loginUrl;
} catch (finalError) {
console.error("[로그인 리다이렉트] 최종 리다이렉트도 실패:", finalError);
// 최후의 수단으로 새로고침
location.reload();
//tmp.removeClass('act');
}
}
}
/**
* 로그아웃 함수 - 모든 팝업을 닫고 로그인 페이지로 이동
*/
function logout() {
redirectToLoginWithCloseAllPopups("로그아웃 되었습니다.");
}
});
});
/**
* 세션 만료 처리 함수 - 모든 팝업을 닫고 로그인 페이지로 이동
* 중요로직: 팝업 환경에서 세션 만료 현재 팝업이 아닌 최상위 창에서 로그인 페이지로 이동
* 모달 닫기 이벤트를 설정하는 함수
* 모달 닫기 버튼 클릭 모달 외부 클릭 모달을 닫는 이벤트를 설정합니다.
* @param {string} modalId - 모달 요소의 ID (기본값: 'modal')
* @param {string} closeBtnSelector - 닫기 버튼의 선택자 (기본값: '.pop-x-btn, .modalclose')
*/
function handleSessionExpired() {
try {
console.log('[세션 만료] 처리 시작');
// 중요로직: 현재 창이 팝업인지 확인
var isPopup = !!(window.opener && !window.opener.closed);
console.log('[세션 만료] 현재 창 팝업 여부:', isPopup);
if (isPopup) {
// 팝업인 경우: 최상위 부모창 찾기
var topWindow = window;
var windowChain = [];
var currentWindow = window;
// 최상위 창까지 탐색
while (currentWindow && currentWindow.opener && !currentWindow.opener.closed) {
windowChain.push(currentWindow);
currentWindow = currentWindow.opener;
topWindow = currentWindow;
// 무한루프 방지 (최대 10단계)
if (windowChain.length > 10) {
console.warn('[세션 만료] 너무 많은 팝업 체인, 탐색 중단');
break;
}
}
console.log('[세션 만료] 팝업 체인 길이:', windowChain.length);
console.log('[세션 만료] 최상위 창 찾음:', !!topWindow);
// 메시지 표시 (현재 팝업에서)
alert("세션이 종료되었습니다. 다시 로그인해주세요.");
// 최상위 창을 로그인 페이지로 이동
if (topWindow && !topWindow.closed) {
try {
topWindow.location.href = (contextPath || '') + loginUrl;
console.log('[세션 만료] 최상위 창 리다이렉트 성공');
} catch (redirectError) {
console.warn('[세션 만료] 최상위 창 리다이렉트 실패:', redirectError);
// 리다이렉트 실패 시 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
}
} else {
// 최상위 창이 닫혀있는 경우 현재 창에서 이동
location.href = (contextPath || '') + loginUrl;
console.log('[세션 만료] 현재 창에서 리다이렉트');
}
function initModalClose(modalId) {
// 기본값 설정
modalId = modalId || 'modal';
// 모든 팝업창 닫기 (약간의 지연 후)
setTimeout(function() {
try {
// 하위 팝업부터 상위 팝업 순서로 닫기
for (var i = 0; i < windowChain.length; i++) {
try {
var popupWindow = windowChain[i];
if (popupWindow && !popupWindow.closed) {
popupWindow.close();
console.log('[세션 만료] 팝업창 닫기 성공:', i + 1);
}
} catch (closeError) {
console.warn('[세션 만료] 팝업창 닫기 실패:', closeError);
}
}
console.log('[세션 만료] 모든 팝업창 닫기 완료');
} catch (e) {
console.warn('[세션 만료] 팝업창 일괄 닫기 실패:', e);
}
}, 300); // 리다이렉트 후 약간의 지연
// '#' 접두사가 없는 경우 추가
if (!modalId.startsWith('#')) {
modalId = '#' + modalId;
}
} else {
// 일반 페이지인 경우 기존 로직 사용
console.log('[세션 만료] 일반 페이지에서 처리');
redirectToLoginWithCloseAllPopups("세션이 종료되었습니다. 다시 로그인해주세요.");
}
// 모달 외부 클릭 시 닫기 (dim 영역 클릭 시)
$(modalId + ' .dim').on('click', function() {
$(modalId).removeClass('act');
});
} catch (e) {
console.error('[세션 만료] 전체 처리 중 오류:', e);
// 모든 처리가 실패한 경우 기본 처리
try {
alert("세션이 종료되었습니다. 다시 로그인해주세요.");
location.href = (contextPath || '') + loginUrl;
} catch (finalError) {
console.error('[세션 만료] 최종 처리도 실패:', finalError);
location.reload();
// ESC 키 입력 시 모달 닫기
$(document).on('keydown', function(e) {
if (e.keyCode === 27 && $(modalId).hasClass('act')) { // ESC key
$(modalId).removeClass('act');
}
}
});
}
/* 5.2 SELECTBOX INITIALIZATION (selectbox 자동 색상 적용) */
/**
* 페이지 로드 모든 selectbox에 자동 색상 적용
*/

Loading…
Cancel
Save