
/*=================================================================================================
 * MARI HOME   ---------------"--<@
 *-------------------------------------------------------------------------------------------------
 * @코드 명칭 : 마리 멀티 업로더 ( 가제 ) 
 * @요약 정보 : 업로더에 필요한 작은 개체 지정 함수들( 되도록 액션이 없는 호출 위주의 ) 모음
 * @파일 이름 : multi_uploader_helper.j
 * @웹용 주소 : 글쓰기등 업로드가 필요한 곳, 파일 탐색기와 같이 파일 미리보기가 필요한 곳에서 외부 파일(js파일)로 호출됨 
 * @호출 파일 : multi_uploader_code.js에 스프레드 연산자로 등록되어 각 요소에서 호출됨
 * @서버 위치 : 마리홈 ( ),  그누보드 ( plugin/multi_uploader/ )
 * @소스 제작 : repter ( 예뜨락 ), 홈페이지 ( https://marihome.net ) 
 * @제작 날짜 : 2023.08.01 ( 최초 제작 시작일 )
 * @소스 설명 : 업로더에서 필요한 작은 기능 메서드들
 * @기타 사항 : 당분간 필요한 업그레이드를 통해서 소스 변경이 자주 일어날 수 있습니다 
 *           자바스크립트 형태 : 객체 리터럴 ( Object Literal )
 *           변수 => 프로퍼티 (Property)   : 프로퍼티 값
 *           함수 => 메서드 (Method)
 * @최종 수정 : 2025.03.26
 * @버전 명시 : 0.9
 *-------------------------------------------------------------------------------------------------
 * Copyright 2023. repter All Rights Reserved.
**===============================================================================================*/ 

// 글로벌 변수 지정
if(typeof(window.MARI) === "undefined") { (function(global) { global.MARI = {}; })(window || global); }
if(typeof(window.MARI.file_uploder) === "undefined") { (function(global) { global.MARI.file_uploder = {}; })(window || global); }

/*=========================================================================================
 * 1. 파일 업로더시 데이터에 관련된 유틸
**----------------------------------------------------------------------------------------*/
if(typeof(window.MARI.file_uploder.helper) === "undefined") {
	MARI.file_uploder.helper  = {        

        /**
         * 마우스로 선택한 곳의 업로더 인덱스 반환
         * @param   {Event}  event  - 발생한 이벤트 객체 (예: 클릭, 마우스 이동 등) 
         * @returns {number} eq_idx - 선택된 업로더의 인덱스 값
         */
        event_eq : function(event){
            const obj_this = MARI.file_uploder.code; 
            const obj_cls  = obj_this.loader_main_cls; 
            // event.target의 부모 요소 중에서 loader_cls 클래스를 가진 가장 가까운 부모 요소
            let allElems   = document.querySelectorAll(obj_cls);
            let searchElm  = event.target && typeof event.target.closest === 'function'
                           ? event.target.closest(obj_cls)
                           : null;
            let index      = Array.from(allElems).indexOf(searchElm);

            // 첫 클릭( 마우스 오버 )한 곳의 업로더와 현재의 포인터 지점의 업로더가 틀리다면 교정 또는 창을 벗어 났다면 교정
            if( index < 0 ){
                if( obj_this.click_eq !== null ){
                    index = Number(obj_this.click_eq); 
                }
            }

            // 이벤트에서 받은 인덱스가 없다면 다른 동작에 의해 저장된 eq_idx를 사용
            let eq_idx     = (index > -1) ? index : obj_this.eq_idx; 
            return eq_idx;
 
        }, 

		/*=========================================================================================
		 * 선택한 버튼류 썸네일 개체등의 인덱스
		**---------------------------------------------------------------------------------------*/
        event_index : function(event, obj_cls){
            const obj_this = MARI.file_uploder.code;  
            let eq_idx     = obj_this.event_eq(event); // 사용 가능하게 설정된 업로더에서의 인덱스
            if( eq_idx < 0 || eq_idx === null ) return false;
            // event.target의 부모 요소 중에서 loader_cls 클래스를 가진 가장 가까운 부모 요소 

            let loaderMain = obj_this.loader_main_obj(eq_idx);
            if (typeof obj_cls !== 'string') return false;
            let allElems   = loaderMain.querySelectorAll(obj_cls);
            let searchElm  = event.target.closest(obj_cls);
            let index      = Array.from(allElems).indexOf(searchElm);
            
            return index;

        }, 

		/*=========================================================================================
		 * 선택한 업로더 모듈 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        module_obj : function( eq_idx ){
            const obj_this   = MARI.file_uploder.code;
            let loaderMain   = obj_this.loader_main_obj(eq_idx);
            let loaderModule = loaderMain.closest(obj_this.uploader_module_cls);
 
            return loaderModule;

        },


        /*=========================================================================================
		 * 선택한 업로더 모듈 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        loader_obj : function( eq_idx ){
            const obj_this   = MARI.file_uploder.code;
            let loaderMain   = obj_this.loader_main_obj(eq_idx);
            let loaderModule = loaderMain.closest(obj_this.loader_cls);
 
            return loaderModule;

        }, 
        

		/*=========================================================================================
		 * 선택한 업로더 메인 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        loader_main_obj : function( eq_idx ){
            const obj_this = MARI.file_uploder.code; 
            let loaderMain = document.querySelectorAll(obj_this.loader_main_cls)[eq_idx];
            
            return loaderMain;

        },


		/*=========================================================================================
		 * 선택한 업로더 백그라운드 개체를 리턴
		**---------------------------------------------------------------------------------------*/
        module_bg_obj : function( eq_idx ){
            const obj_this = MARI.file_uploder.code; 
            let bgZone = document.querySelectorAll(obj_this.module_bg_cls)[eq_idx];
            
            return bgZone;

        },


		/*=========================================================================================
		 * 선택한 업로더 메인 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        file_zone_obj : function( eq_idx ){
            const obj_this = MARI.file_uploder.code;
            // .file_zone 요소를 선택
            let fileZone = document.querySelectorAll(obj_this.file_zone_cls)[eq_idx];

            return fileZone;

        },


   		/*=========================================================================================
		 * 선택한 업로더 메인 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        file_main_obj : function( eq_idx ){
            const obj_this = MARI.file_uploder.code;
            // .file_zone 요소를 선택
            let file_main = document.querySelectorAll(obj_this.file_main_cls)[eq_idx];

            return file_main;

        },  


		/*=========================================================================================
		 * 선택한 업로더 UL 그룹 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        ul_obj : function( eq_idx ){
            let obj_this   = MARI.file_uploder.code;  
            let loaderMain = obj_this.loader_main_obj(eq_idx);
            let ulObj      = loaderMain.querySelector(obj_this.file_list_cls) || null;// .file_list 클래스의 ul 

            return ulObj;

        },


		/*=========================================================================================
		 * 업로더에서 선택한 LI 개체를 리턴 ( 사용 가능하게 설정된 )
		**---------------------------------------------------------------------------------------*/
        li_obj : function( eq_idx ){
            let obj_this   = MARI.file_uploder.code; 
            let loaderMain = obj_this.loader_main_obj(eq_idx);
            if(typeof(loaderMain) === 'undefined'){ return false; }
            let liObj      = loaderMain.querySelectorAll(obj_this.one_file_cls) || null;// .one_file 클래스의 li

            return liObj;
            
        },


		/*=========================================================================================
		 * 선택된 업로더에서의 드래그시 지정되는 포커스 판넬 개체를 리턴 ( 드래그시 지정되는 옅은 파랑색 하이라이트 판넬 )
		**---------------------------------------------------------------------------------------*/
        getFocusPanel : function( eq_idx ){
            let obj_this   = MARI.file_uploder.code;  
            let loaderMain = obj_this.loader_main_obj(eq_idx);
            let pannelObj  = loaderMain.querySelector(obj_this.focus_pannel_cls) || null;// .one_file 클래스의 li

            return pannelObj;

        },


		/*=========================================================================================
		 * 선택된 업로더에서의 판넬 개체를 리턴 ( 드래그시 지정되는 옅은 파랑색 판넬 )
		**---------------------------------------------------------------------------------------*/
        getDropZone : function( eq_idx ){
            let obj_this    = MARI.file_uploder.code; 
            let loaderMain  = obj_this.loader_main_obj(eq_idx);
            let dropZoneObj = loaderMain.querySelector(obj_this.drop_zone_cls) || null;// .one_file 클래스의 li
            
            return dropZoneObj;

        },


		/*=========================================================================================
		 * 선택된 파일명이 들어간 span 개체를 리턴
		**---------------------------------------------------------------------------------------*/
        getNameSpan : function(eq_idx, editIdx){
            let obj_this = MARI.file_uploder.code; 
            let li_obj   = obj_this.li_obj(eq_idx);
            let nameDiv  = li_obj[editIdx].querySelector(obj_this.file_name_in_cls); // 단일 요소 선택 
            let nameSpan = nameDiv.querySelector(obj_this.file_name_cls);
            
            return nameSpan;

        },


		/*=========================================================================================
		 * 선택한 곳이 썸네일인지 아닌지
		**---------------------------------------------------------------------------------------*/
        getTargetType : function(event) {
            let obj_this    = MARI.file_uploder.code; 
            let target_type = event && event.target ? obj_this.is_thumbnail(event) : null;
            return target_type;
        },


        /**
         * Ul의 최대 넓이를 지정 shape1, shape2, shape3에서 사용
        **/
        getListMaxWidth : function( eq_idx ){
            let obj_this      = MARI.file_uploder.code;  
            let loaderMain    = obj_this.loader_main_obj(eq_idx);
            let ul_obj        = obj_this.ul_obj(eq_idx); 
            let li_obj        = obj_this.li_obj(eq_idx);

            if(!li_obj[0]) return false;
            let totalCnt      = obj_this.file_count_return(eq_idx, 'totalCnt');  // 업로드 전체 갯수
            let list_shape    = obj_this.list_shape[eq_idx];  
            let listRect      = li_obj[0].getBoundingClientRect();
            let paddingLeft   = parseFloat(getComputedStyle(li_obj[0]).paddingLeft);   // 패딩
            let paddingRight  = parseFloat(getComputedStyle(li_obj[0]).paddingRight);  // 패딩
            let paddingTop    = parseFloat(getComputedStyle(li_obj[0]).paddingTop);    // 패딩
            let paddingBottom = parseFloat(getComputedStyle(li_obj[0]).paddingBottom); // 패딩 
            let paddingLR     = paddingLeft + paddingRight;
            let maxWidth      = ((listRect.width + paddingLR) *( totalCnt + 0)) + 25;//22
            if(list_shape === 'shape1' || list_shape === 'shape2' || list_shape === 'shape3' ){ 
                // 리스트의 최대 넓이를 리스트 갯수에 맞춰서 지정한다 
                if(totalCnt > 1 ){
                    loaderMain.querySelector('.file_list').style.maxWidth = maxWidth+'px'; 
                } else { 
                    loaderMain.querySelector('.file_list').removeAttribute('style'); 
                }
            } else {
                loaderMain.querySelector('.file_list').removeAttribute('style'); 
            }

        },


        /**
         * 현재 라인에서 가장 높은 이미지의 높이에 맞춰 나머지 높이를 맞춘다
        **/
        equalizeImageHeights : function( eq_idx,  objType ='', listShape = '', listIdx) {
            const obj_this    = MARI.file_uploder.code;
            let list_shape    = obj_this.list_shape[eq_idx];   
            let ul_obj        = obj_this.ul_obj(eq_idx); // ul 요소
            let li_obj        = obj_this.li_obj(eq_idx); // ul 안의 li 요소들  
            let file_main_obj = obj_this.file_main_obj(eq_idx); // file_main 
            let fileMainRect  = file_main_obj.getBoundingClientRect();
            let fileMainWd    = fileMainRect.width;
            let paddingLeft   = parseFloat(getComputedStyle(ul_obj).paddingLeft);   // 패딩
            let paddingRight  = parseFloat(getComputedStyle(ul_obj).paddingRight);  // 패딩
            let ulPadding     = paddingLeft + paddingRight;                         // 패딩
            let li_cnt        = li_obj.length; // li의 개수
            let plusWidth     = 0;
            let rows          = [];//MARI.file_uploder.code.rowsData[eq_idx];
            let currentRow    = [];

            // li 요소들을 줄 단위로 그룹화
            for (let i = 0; i < li_cnt; i++) {
                let liWidth      = li_obj[i].offsetWidth;           // li의 너비
                let styles1      = getComputedStyle(li_obj[i]);     // imgWrap의 스타일 가져오기
                let marginsL     = parseFloat(styles1.marginLeft);  // 
                let marginsR     = parseFloat(styles1.marginRight); // 
                let margins      = marginsL + marginsR;
			    let has_yscroll  = obj_this.has_yscroll(event, eq_idx);
                let scrollWd     = has_yscroll ? 12 : 0; // 스크롤이 있으면 12, 없으면 0
                let objWidth     = plusWidth + liWidth + margins + scrollWd + 0; // 15 여유분
                let tgtWidth     = fileMainWd - ulPadding;
                let imgWrap      = li_obj[i].querySelector('.upload_thumb_wrap'); 
                let imgThumb     = li_obj[i].querySelector('.upload_thumb'); 
                let fileName     = li_obj[i].querySelector('.file_name').innerText; 
                let dataCode     = li_obj[i].getAttribute('data-code'); 
                let imgWidth     = imgThumb.offsetWidth; // 넓이를 숫자로 변환 
                let imgHeight    = imgThumb.offsetHeight; // 높이를 숫자로 변환 
                // 모듈 넓이를 기준으로 리스트가 몇개 들어갈 수 있는지 분별한다
                if (objWidth > tgtWidth) {
                    rows.push(currentRow); // 현재 까지 받은 것을 row 배열에 넣는다 
                    plusWidth  = 0;        // 다음 줄을 받기 위한 초기화
                    currentRow = [];       // 다음 줄을 받기 위한 초기화
                }
                plusWidth +=liWidth;
                let infoAry =[i, fileName, dataCode, imgWidth, imgHeight];
                currentRow.push(infoAry);     // 새로운 줄 생성 
            }// end i
        
            // 다돌고 남은 currentRow에 남은 것을 row 배열에 넣는다
            if (currentRow.length > 0) {
                rows.push(currentRow); // 마지막 줄 추가
            }
            
            //현재 줄별로 담겨 있는 데이터들
            MARI.file_uploder.code.rowsData[eq_idx] = rows; 
            if((listIdx !== null && li_cnt == listIdx + 1 )||  objType === 'resizeMouseUp'){
                // 히스토리 입력
                let msgAry = ['현재 줄별로 담겨 있는 데이터들', rows];
                obj_this.historyEvent(eq_idx, msgAry, 'pink'); 
            }

            // 각 줄에서 가장 높은 이미지 찾기 및 높이 맞춤 
            rows.forEach((row, index1) => { 
                let maxHeight = 0; 
                let minHeight = Infinity; // 최소 높이를 무한대로 초기화

                // 줄 내에서 가장 높은, 낮은 이미지의 높이를 갱신해서 받아둔다
                row.forEach((rowData, index2) => {
                    const height = parseFloat(rowData[4]); // 높이를 숫자로 변환
                    maxHeight = Math.max(maxHeight, height);
                    minHeight = Math.min(minHeight, height);
                });

                // 받아둔 가장 높은, 낮은 값으로 같은줄의 리스트들의 높이를 갱신한다
                row.forEach((rowData, index3) => {                
                    const  idx     = rowData[0];
                    const  imgWrap = li_obj[idx].querySelector('.upload_thumb_wrap'); 
                    imgWrap.style.minHeight =  maxHeight + 'px';
                });

            });

        },


        equalizeImageHeights2 : function( eq_idx, listShape = '', changeShape ='') {
            const obj_this    = MARI.file_uploder.code;
            let list_shape    = obj_this.list_shape[eq_idx];   
            let ul_obj        = obj_this.ul_obj(eq_idx); // ul 요소
            let paddingLeft   = parseFloat(getComputedStyle(ul_obj).paddingLeft);   // 패딩
            let paddingRight  = parseFloat(getComputedStyle(ul_obj).paddingRight);  // 패딩
            let paddingTop    = parseFloat(getComputedStyle(ul_obj).paddingTop);    // 패딩
            let paddingBottom = parseFloat(getComputedStyle(ul_obj).paddingBottom); // 패딩 
            let ulWidth       = ul_obj.clientWidth  - paddingLeft - paddingRight;  // ul의 너비
            let ulHeight      = ul_obj.clientHeight - paddingTop  - paddingBottom;
            let li_obj        = obj_this.li_obj(eq_idx); // ul 안의 li 요소들 
            let li_cnt        = li_obj.length; // li의 개수
            let currentWidth  = 0;
            let rows          = [];
            let currentRow    = []; 
            let file_main_obj = obj_this.file_main_obj(eq_idx); // file_main 
            let fileMainRect  = file_main_obj.getBoundingClientRect();
            let mainPaddingLeft  = parseFloat(getComputedStyle(file_main_obj).paddingLeft);   // 패딩
            let mainPaddingRight = parseFloat(getComputedStyle(file_main_obj).paddingRight);  // 패딩
			let has_xscroll   = obj_this.has_xscroll(event, eq_idx);
			let has_yscroll   = obj_this.has_yscroll(event, eq_idx);
                
            // shape1, shape2, shape3 이외 나머지는 적용시키지 않음
            if(!(listShape == 'shape1' || listShape == 'shape2'|| listShape == 'shape3')){
                return false;
            }

            // li 요소들을 줄 단위로 그룹화
            for (let i = 0; i < li_cnt; i++) {
                let thumbImg      = li_obj[i].querySelector('.upload_thumb_wrap img'); 
                let imgWrap       = li_obj[i].querySelector('.upload_thumb_wrap'); 
                let liWidth       = li_obj[i].offsetWidth; // li의 너비
                let liHeight      = li_obj[i].offsetHeight;
                let styles1       = getComputedStyle(li_obj[i]); // imgWrap의 스타일 가져오기
                let styles        = getComputedStyle(imgWrap); // imgWrap의 스타일 가져오기
                let paddingTop    = parseFloat(styles.paddingTop); // 패딩 위쪽 값
                let paddingBottom = parseFloat(styles.paddingBottom); // 패딩 아래쪽 값
                let totalHeight   = thumbImg.offsetHeight + paddingTop + paddingBottom; // 높이 + 패딩 값 합산 
                let marginsL      = parseFloat(styles1.marginLeft); // 
                let marginsR      = parseFloat(styles1.marginRight); // 
                let margins       = marginsL + marginsR; 
                let scrollWd      = 0;

                if (has_yscroll === true) { // 스크롤이 생겼다면 드롭바를 즉시 감춘다
                    scrollWd      = 12;
                }
                 
                // 한줄의 넓이 ( file_main에서 file_list의 패딩까지를 빼야 리스트의 측면까지의 거리가 나온다)
                if (currentWidth + liWidth + margins + scrollWd > fileMainRect.width - (paddingLeft + paddingRight)) { 
                    rows.push(currentRow); // 현재 줄 저장
                    currentRow   = [];     // 새로운 줄 생성
                    currentWidth = 0;
                }

                // 원본 높이를 저장 (한 번만 저장)
                if(changeShape){ // 변경
                    imgWrap.dataset.originalHeight = totalHeight;
                } else { // 없다면 입력
                    if (!imgWrap.dataset.originalHeight) {
                        imgWrap.dataset.originalHeight = totalHeight;
                    }
                }

                currentRow.push(imgWrap); // 현재 줄에 li 추가
                currentWidth += liWidth;
            }
            
            if (currentRow.length > 0) {
                rows.push(currentRow); // 마지막 줄 추가
            }

            // 각 줄에서 가장 높은 이미지 찾기 및 높이 맞춤
            rows.forEach((row, index1) => {
                let maxIdx    = null;
                let minIdx    = null;
                let maxHeight = 0; 
                let minHeight = Infinity; // 최소 높이를 무한대로 초기화

                // 줄 내에서 가장 높은 이미지의 높이 계산
                row.forEach((imgWrap, index2) => {
                    if (imgWrap) {
                        const height = parseFloat(imgWrap.dataset.originalHeight); // 높이를 숫자로 변환
                        if (height > maxHeight) {
                            maxHeight = height;
                            maxIdx = index2; // 최대 높이의 인덱스 갱신
                        }
                        if (height < minHeight) {
                            minHeight = height;
                            minIdx = index2; // 최소 높이의 인덱스 갱신
                        }
                    }  
                });

                // 현재줄 내의 모든 이미지 높이를 가장 높은 이미지로 설정
                row.forEach(imgWrap => { 
                    if (imgWrap) {
                        imgWrap.style.height = `${maxHeight}px`;
                    }
               });
            });

        },


        /**
         * select_ary 를 idx기준으로 오름차순 정렬
        **/
        sortByIdx : function(data){
            // idx를 기준으로 정렬
            const sorted = data.idx
                .map((value, index) => ({
                    objType : data.objType[index],
                    idx     : value,
                    code    : data.code[index],
                    name    : data.name[index]
                }))
                .sort((a, b) => a.idx - b.idx);

            // 정렬된 데이터 다시 구조화
            return {
                objType : sorted.map(item => item.objType),
                idx     : sorted.map(item => item.idx),
                code    : sorted.map(item => item.code),
                name    : sorted.map(item => item.name)
            }; 
        },


        /**
         * 데이터 코드에서 인텍스를 다시 재설정할 때 사용
        **/
        updateDataCode : function(dataCode, newLastDigit) {
            if( dataCode )
            return dataCode.replace(/_\d+$/, `_${newLastDigit}`);
            else
            return false;
        },


        /**
         * 데이터에서 특정 개체를 지정 위치로 순서를 변경
         * 
         * drag_selection_mouse_up -> ghostMoveAfter_AddDom -> moveMultipleItemsInArray
         * ----------------------------------------------------------------------------------------
         * 1.리스트를 기준으로 루프를 돌려서 미리 만들어 높은(newAry,modifyAry) 배열에 
         *   리스트의 타입별로(New,Modify) 데이터 코드를(dataCode) 받는다
         * 2.받아 놓은 코드 값을 이용해서 원본 데이터들을 코드값 기준으로 재정렬 시킨다
         *   ( 코드 값을 이용해서 데이터의 속성에 접근하거나 수정을 할 때 사용하므로 필히 필요하다 )
         * 3. setDataCode 를 이용해 데이터의 바뀐 인덱스등에 맞게 데이터 코드, 데이터 인덱스등을 순서에 맞게 바꾼다
         *    HTML 속성값의 data-code 또한 리스트 순서에 맞게 코드값을 바꾼다
        **/
        moveMultipleItemsInArray: function (event, eq_idx, selectedAry, toIndex) {
            const obj_this = MARI.file_uploder.code;
            const li_obj   = obj_this.li_obj(eq_idx); // 리스트
            const liLen    = li_obj.length;
            const dTaAry   = obj_this.dTa_Ary[eq_idx]; // New, Modify가 담기는 데이터 배열
            let modifyAry  = [], newAry = [];

            // 데이터 코드를 Modify와 New 배열로 분류
            for (let i = 0; i < liLen; i++) {
                const objType  = obj_this.getMakeType(eq_idx, i);
                const dataCode = obj_this.getDataCode(eq_idx, i);
                if (objType === 'Modify') modifyAry.push(dataCode);
                else if (objType === 'New') newAry.push(dataCode);
            }

            // 서버에 저장된 수정용 데이터라면
            if (modifyAry.length > 0) {
                dTaAry.modify_files = modifyAry.map(code => 
                    dTaAry.modify_files.find(item => item.dataCode === code)
                );
            }

            // 새로 업로드된 데이터라면
            if (newAry.length > 0) {
                // 파일 리스트를 일반 배열로 변환
                const newDataAry = Array.from(dTaAry.new_files.files);
                // newAry 순서대로 정렬된 새 배열 생성
                const sortNewAry = newAry.map(code => 
                    newDataAry.find(file => file.dataCode === code)
                );
                // DataTransfer를 사용해 새로운 FileList 생성
                const dataTransfer = new DataTransfer();
                sortNewAry.forEach(file => dataTransfer.items.add(file));
                // 전역 객체의 FileList 업데이트
                dTaAry.new_files = dataTransfer;
            }

            // DOM의 dataCode와 관련된 데이터를 갱신
            obj_this.setDataCode(event, eq_idx);

        },
        

        /**
         * 돔의 dataCode, 데이터의 dataCode, 인덱스등 업데이트
         * 인덱스등 필요 데이터 갱신을 위해서 전체를 한번 돌림
        **/
        setDataCode: function (event, eq_idx) {
            const obj_this = MARI.file_uploder.code;
            const li_obj = obj_this.li_obj(eq_idx);
            let m = 0, n = 0;
 
            obj_this.select_ary_reset(event, eq_idx); // 배열을 비운다

            li_obj.forEach((li, i) => {
                const objType = obj_this.getMakeType(eq_idx, i);
                const dataCode = obj_this.getDataCode(eq_idx, i);
                const count = objType === 'Modify' ? m++ : objType === 'New' ? n++ : null;

                if (count !== null) {
                    const updatedDataCode = obj_this.updateDataCode(dataCode, count + 1);
                    const info_Ary = { dataIdx: count, dataCode: updatedDataCode };
                    obj_this.setFileInfo(event, eq_idx, objType, count, info_Ary); // 데이터코드와 데이터 인덱스등을 맞춤
                    li.setAttribute("data-code", updatedDataCode); // 리스트 속성을 맞춤
                }

                // 선택된 리스트들을 선택 배열에 다시 넣어준다
                if( li.className ==='one_file thumb_chk3' || li.className ==='one_file thumb_chk4' || 
                    li.className ==='one_file thumb_chk1'  || li.className ==='one_file thumb_chk2' ){ 
                    obj_this.set_drag_select_ary(event, objType, 'add', eq_idx, i, 'thumbnail', 'dragAct3');
                }
            });

        },


		/*=========================================================================================
		 * 리스트 클릭시 클릭된 곳이 썸네일인지 배경인지 리턴
		**---------------------------------------------------------------------------------------*/
        is_thumbnail : function(event) {
            let cls = event && event.target ? event.target.className : ''; 
            let target_type = null;
            if (cls) {
                target_type = ( cls.indexOf('contentDiv') > -1 || 
                                cls.indexOf('choice_div') > -1 || 
                                cls.indexOf('one_file') > -1 || 
                                cls.indexOf('upload_thumb') > -1 ||  
                                cls.indexOf('file_name') > -1 ||  
                                cls.indexOf('file_icon') > -1 ||  
                                cls.indexOf('thumb_bt') > -1 || 
                                cls.indexOf('del_bt') > -1 ) ? 'thumbnail' : 'around';
            }

            return target_type;

        },


        /**
         * 업로드 전체 갯수 넣어주기, 대표 썸네일 선택, 선택된 갯수가 있다면 초기화, 전체 파일 사이즈 넣기, 끝나는 시점에 에니메이션
         */
        setTotalElem : function(eq_idx, totalCnt, setThumbIdx){ 
		 	let obj_util    = MARI.file_uploder.util;
            let obj_this    = MARI.file_uploder.code; 
            let loaderMain  = obj_this.loader_main_obj(eq_idx);
            let element     = loaderMain.querySelector('.total_in_file_cnt');
            let total_size  = obj_this.get_file_size(eq_idx, 'total');  // 토탈 파일 사이즈
            let dataMbSize  = obj_util.bite_to_mega(total_size);
            let dataKbSize  = obj_util.bite_to_killo(total_size);
            let total_size2 = ( dataKbSize > 1000 ) ? dataMbSize : dataKbSize;  // 표기 파일 크기 1000이 넘어서면 메가바이트로 작으면 킬로바이트로 표기
            let file_units  = ( dataKbSize > 1000 ) ? 'MB' : 'KB';              // 표기 파일 크기
 
            element.innerHTML = totalCnt;                                       // 전체 갯수 넣기 
	  	    obj_this.thumb_choice(eq_idx, setThumbIdx);                         // 대표 썸네일 선택  
            loaderMain.querySelector('.del_file_cnt').innerHTML  = 0;           // 선택된 갯수가 있다면 초기화 
			MARI.file_uploder.code.total_size = total_size;                     // 전체 사이즈 바이트
            loaderMain.querySelector('.up_size_num').innerHTML   = total_size2; // 메가 바이트 또는 킬로 바이트로 사이즈를 표기
            loaderMain.querySelector('.up_size_units').innerHTML = file_units;  // 단위 표기

			// 끝나는 시점에 에니메이션
		 	obj_this.totalInFileAni(eq_idx, totalCnt);

        },


		/*=========================================================================================
		 * 파일의 갯수를 리턴한다
		**---------------------------------------------------------------------------------------*/
        file_count_return : function(eq_idx, returnType = 'totalCnt'){
            let obj_this   = MARI.file_uploder.code; 
            let resultMsg  = null;
            let dTaAry     = MARI.file_uploder.code.dTa_Ary[eq_idx];
            let tempAry    = obj_this.temp_Ary[eq_idx] || null;                                // dTa_Ary에 담기 위한 임시 배열 ( 파일 업로드 행위마다 리셋 )
            let modifyCnt  = dTaAry.modify_files.filter(item => item !== null).length;         // 수정용 파일로 담긴 파일 갯수
            let newFiles   = dTaAry.new_files.files;
            let newCnt     = Array.from(newFiles).filter(file => file.name !== 'null').length; // 새로운 파일로 담긴 파일 갯수 
            let tempCnt    = tempAry !== null ? parseInt(tempAry.length) : 0;  // 파일 업로더 전체 갯수
            let totalCnt   = modifyCnt + newCnt;// + file_cnt;
          //newFileAdd에서 가져옴 둘의 차이점???
          //let totalCnt   = modifyCnt + newCnt + file_cnt;          // 수정용 + 새로 올린거 + 새로 올려 놓은 받아 놓은 것 

            if( returnType === 'totalCnt'){ // 전체 갯수
                resultMsg  = totalCnt;
            }
            else
            if(returnType === 'modifyCnt'){// 수정용 갯수
               resultMsg   = modifyCnt;
            }
            else
            if(returnType === 'newCnt'){  // 새로 업로드 갯수( 누적 )
               resultMsg   = newCnt;
            }
            else
            if(returnType === 'tempCnt'){ // 현재 템프에 업로드된 갯수 ( 새로 인풋 클릭시마다 올려진 갯수 )
               resultMsg   = tempCnt;
            }
            else
            if(returnType === 'upTotalCnt'){ // 전체 갯수
               resultMsg   = tempCnt + modifyCnt;
            }

            return resultMsg;

        },


        selectCnt : function(eq_idx){
            const obj_this = MARI.file_uploder.code;
            let select_ary = MARI.file_uploder.code.drag_select_ary; 
            let select_cnt = (typeof select_ary[eq_idx] !== 'undefined' && Array.isArray(select_ary[eq_idx]['idx'])) 
                           ? select_ary[eq_idx]['idx'].length 
                           : 0;

            // 현재의 갯수를 전역에서 편하게 쓰기 위해서 
            obj_this.selectCnt2 = select_cnt;

            return select_cnt;

        },
            
        selectCnt2 : 0,

		/*=================================================
		 * 파일의 사이즈를 리턴
		**-----------------------------------------------*/
		get_file_size : function(eq_idx, returnType = 'total'){
            let obj_this       = MARI.file_uploder.code;  
            let loaderMain     = obj_this.loader_main_obj(eq_idx);
            let li_obj         = obj_this.li_obj(eq_idx);
            let dTaAry         = obj_this.dTa_Ary[eq_idx];  
            let modifyAry      = dTaAry.modify_files;
            let newMakeAry     = dTaAry.new_files.files;
            let modifyLen      = modifyAry.length;
            let newMakeLen     = newMakeAry.length;
            let modyfiDataByte = 0;
            let newDataByte    = 0;
            let dataByte       = 0; 

            for(let i=0; i<modifyLen; i++){ 
                if(dTaAry.modify_files[i] && dTaAry.modify_files[i].dataByteSize)
                modyfiDataByte += parseFloat(dTaAry.modify_files[i].dataByteSize);
            }

            for(let i=0; i<newMakeLen; i++){ 
                if(dTaAry.new_files.files[i] && dTaAry.new_files.files[i].dataByteSize)
                newDataByte += parseFloat(dTaAry.new_files.files[i].dataByteSize); 
            }
 
            if( returnType === 'modify' ){ dataByte = modyfiDataByte; } 
            else 
            if ( returnType === 'new' )  { dataByte = newDataByte;    } 
            else 
            if ( returnType === 'total' ){ dataByte = modyfiDataByte + newDataByte; } 
   
            return dataByte;
 
        },
 

		/*=========================================================================================
		 * totalInFileAni 에니메이션
		**---------------------------------------------------------------------------------------*/ 
		totalInFileAni : function(eq_idx, totalCnt){
			let obj_this      = MARI.file_uploder.code;  
            let loaderMain    = obj_this.loader_main_obj(eq_idx);
            let targetElement = loaderMain.querySelector('.total_in_file_img');  

            // 요소에 'totalInFileAni' 클래스가 있는지 확인하고, 있으면 제거
            if (targetElement.classList.contains('total_in_file_ani')) {
                targetElement.classList.remove('total_in_file_ani'); // 초기화
            }

            // setTimeout을 사용하여 500ms 후에 'totalInFileAni' 클래스를 다시 추가
            let time_var2 = setTimeout(function() {
                targetElement.classList.add('total_in_file_ani'); // 애니메이션 추가
                clearTimeout(time_var2);
            }, 250);

		},


		total_in_file_ani : function(obj_eq_idx, totalCnt){
            // 몇번째 파일 업로더인지에 대한 인덱스 설정
            let obj_this = MARI.file_uploder.code;
            let eq_idx = obj_eq_idx;

            // 카메라 아이콘 배경색 변경
            if (totalCnt > 0) {
                let cameraKey = document.querySelectorAll('.camera_key')[eq_idx];
                let cameraKeyOn = document.querySelectorAll('.camera_key_on')[eq_idx];
                cameraKey.classList.add('camera_key_on');
                cameraKey.classList.remove('camera_key');
            }

            // 업로드 전체 갯수 애니메이션
            let totalInFileImg = document.querySelectorAll('.total_in_file_img')[eq_idx];
            if (totalInFileImg.classList.contains('total_in_file_ani')) {
                totalInFileImg.classList.remove('total_in_file_ani');
            }

            // 애니메이션을 위한 타이머 설정
            let time_var2 = setTimeout(function() {
                totalInFileImg.classList.add('total_in_file_ani');
                clearTimeout(obj_this.set_time_var2);
            }, 500);

            // setTimeout 변수 저장
            obj_this.set_time_var2 = time_var2;

		},


		/*=========================================================================================
		 * 선택한 리스트의 타입이 New인지 Modify인지 리턴
		**---------------------------------------------------------------------------------------*/    
        getDataCode : function(eq_idx, evt_idx) {
            let obj_this = MARI.file_uploder.code;
            let li_obj = obj_this.li_obj(eq_idx);

            return (evt_idx >= 0 && li_obj[evt_idx]) ? li_obj[evt_idx].getAttribute('data-code') : false;

        },


		/*=========================================================================================
		 * 선택한 리스트의 데이터 코드 리턴
		**---------------------------------------------------------------------------------------*/   
        getListDataCode : function(eq_idx, evt_idx) {
            let li_obj = MARI.file_uploder.code.li_obj(eq_idx);
            return evt_idx >= 0 && li_obj[evt_idx]?.getAttribute('data-code') || false;

        },


		/*=========================================================================================
		 * 선택한 리스트의 데이터에서 인덱스 리턴
		**---------------------------------------------------------------------------------------*/
        getListDataAryIdx : function(eq_idx, evt_idx) { // getListDataIdx 대신 함수명 변경
            const li_obj = MARI.file_uploder.code.li_obj(eq_idx);
            if (evt_idx >= 0 && li_obj?.[evt_idx]?.getAttribute('data-code')) {
                return li_obj[evt_idx].getAttribute('data-code').split('_').pop();
            }
            return false;

        },


		/*=========================================================================================
		 * 선택한 리스트의 리스트 순서 리턴
		**---------------------------------------------------------------------------------------*/    
        getListDataAryIdx_원본 : function(eq_idx,evt_idx){
            if(evt_idx < 0) return false; 
            let obj_this   = MARI.file_uploder.code;   
            let dataCode   = obj_this.getListDataCode(eq_idx, evt_idx);  
            if(!dataCode) return false;
            let codeExp    = dataCode.split("_");  
            let makeType   = codeExp[0];  // 로드 이후이므로 M,N둘다
            let eqIdx      = codeExp[1]; 
            let upTime     = codeExp[2];
            let aryIdx     = codeExp[3];
            let objType    = (makeType === 'N') ? 'New' : 'Modify';

            return aryIdx;

        },


		/*=========================================================================================
		 * 선택한 리스트의 타입이 New인지 Modify인지 리턴
		**---------------------------------------------------------------------------------------*/    
        getMakeType: function(eq_idx, evt_idx) {
            let obj_this = MARI.file_uploder.code;
            let li_obj = obj_this.li_obj(eq_idx);

            if (evt_idx < 0 || !li_obj[evt_idx]) return false;

            let dataCode = li_obj[evt_idx].getAttribute('data-code');

            return dataCode.startsWith('N') ? 'New' : 'Modify';

        },


		/*=========================================================================================
		 * 포커스 판넬 보이지 않게하기
		**---------------------------------------------------------------------------------------*/   
        focusPanelHide : function(){
            let obj_this    = MARI.file_uploder.code;   
            let eq_idx      = obj_this.event_eq(event);
            let focus_panel = obj_this.getFocusPanel(eq_idx); // 하일라이트 판넬
            // 포커스 판넬 리셋 
            if(focus_panel){
                focus_panel.style.left    = '0px';
                focus_panel.style.top     = '0px';
                focus_panel.style.width   = '0px';
                focus_panel.style.height  = '0px'; 
                focus_panel.style.display = 'none';
            }

        },


        // 드래그, 리사이즈등에 사용되는 커버 판넬
        // 드래그, 리사이즈등을 할때 마우스 커서가 마우스 이동시 변경되지 않게 하기 위해서 판넬 하나를 만드는데 사용 :: 크게 중요 기능은 아님
        helperDiv_create : function(event, cursorType = 'default'){
		 	const obj_util  = MARI.file_uploder.util;
            const obj_this  = MARI.file_uploder.code;
            if ( obj_this.helperDomeId === null) {
                obj_this.helperDomeId = 'helper'+obj_util.getCurrentTimeInMicroseconds() + '';
            }

            if (!document.getElementById(obj_this.helperDomeId)) {
                const newDiv        = document.createElement('div');
                newDiv.id           = obj_this.helperDomeId; // 아이디 설정
                newDiv.className    = 'helperDiv';
                newDiv.style.cursor = cursorType;     // 커서 모양을 포인터로 설정 
                newDiv.setAttribute("target_class", event.target.className); // 속성 설정 필요시 바꿔서 사용할 것
                document.body.appendChild(newDiv);    // body에 추가
            }

        },


		/*=========================================================================================
		 * 스크롤바의 넓이
		**---------------------------------------------------------------------------------------*/
        scrollbarWD : function(){
            let scrollbarWidth = (window.innerWidth - document.documentElement.clientWidth);

            return parseInt(scrollbarWidth);

        },


        scrollbarHT : function(){
            let scrollbarHeight = (window.innerHeight - document.documentElement.clientHeight);

            return parseInt(scrollbarHeight);

        }, 


		/*=========================================================================================
		 * x-scroll바가 있는지에 대한 리턴
		**---------------------------------------------------------------------------------------*/
        has_xscroll : function(event, obj_eq) {
            let obj_this      = MARI.file_uploder.code;
            let eq_idx        = obj_eq;
            let file_main_obj = obj_this.file_main_obj(eq_idx); // file_main 
            let x_scroll      = false;

            if( file_main_obj ){  
                if (Math.round(file_main_obj.scrollWidth) > Math.round(file_main_obj.clientWidth)) {
                    x_scroll = true; 
                }
            }

            return x_scroll;

        },

		/*=========================================================================================
		 * y-scroll바가 있는지에 대한 리턴
		**---------------------------------------------------------------------------------------*/
        has_yscroll : function(event, obj_eq) {  
            let obj_this      = MARI.file_uploder.code;
            let eq_idx        = obj_eq; 
            let file_main_obj = obj_this.file_main_obj(eq_idx); // file_main  
            let y_scroll      = false;

            if( file_main_obj ){ 
                if (Math.round(file_main_obj.scrollHeight) > Math.round(file_main_obj.clientHeight)) {
                    y_scroll = true; 
                }
            }

            return y_scroll;

        },


		/*=========================================================================================
		 * 미리보기창 드래그바 드래그시 감춤 보이기 설정
		**---------------------------------------------------------------------------------------*/ 
		drag_bar_line_dp : function(event, obj_eq_idx, objType){
		 	let obj_util      = MARI.file_uploder.util;
            let obj_this      = MARI.file_uploder.code;
 			let eq_idx        = obj_eq_idx;//  obj_this.eq_idx;
			let has_xscroll   = obj_this.has_xscroll(event, eq_idx);
			let has_yscroll   = obj_this.has_yscroll(event, eq_idx);
            let preview_mode  = String(obj_this.preview_mode[eq_idx]); // 파일 미리 보기 창 열려 있는지에 대한 플래그  
            let detail_mode   = String(obj_this.detail_mode[eq_idx]);  // 파일 상세 보기 창 열려 있는지에 대한 플래그  
            let loaderMain    = obj_this.loader_main_obj(eq_idx);
            let drop_zone_obj = obj_this.getDropZone(eq_idx);  
            let dragBar       = loaderMain ? loaderMain.querySelector('.drag_bar') : null;
            let dragBarCover  = loaderMain ? loaderMain.querySelector('.drag_bar_cover') : null;

            if(dragBar){ 
                if (has_yscroll === true) { // 스크롤이 생겼다면 드롭바를 즉시 감춘다
                    dragBar.style.opacity = '0';
                    if (preview_mode === 'open' || detail_mode === 'open') { // 열려 있을 때만 보이도록
                        dragBar.style.display = 'block';

                    }
                } else { // 스크롤바가 없다면 열려 있을 경우 드롭바를 보여준다

                    if (preview_mode === 'open' || detail_mode === 'open') { // 열려 있을 때만 보이도록
                        if(objType ==='fadeIn'){
                            obj_util.fadeIn(dragBar, 150, 350); //지속시간, 딜레이시간
                        } else {
                            dragBar.style.opacity = '1'; 
                        }

                        dragBar.style.display = 'block'; 
                    }

                    if (preview_mode === 'close' || detail_mode === 'close') { // 열려 있을 때만 보이도록
                        if(objType ==='fadeOut'){
                            obj_util.fadeOut(dragBar, 150, 350); //지속시간, 딜레이시간 
                        }
                    }
                }
            }

		},


		/*=========================================================================================
		 * 디버깅을 위한 로그 ::: 관리자일 경우만 
		**---------------------------------------------------------------------------------------*/ 
        log : function(msg1, msg2, viewType = 'No'){

            if (MARI.file_uploder.code.isAdmin === true) {
                const obj_this = MARI.file_uploder.code;
                const err = new Error();
                const stackLines = err.stack.split('\n');
                const lineInfo = stackLines[2]?.trim() || ''; // 2번째 줄에서 라인 정보 가져오기

                // 파일 경로 및 라인 번호 추출
                const fileInfoMatch = lineInfo.match(/(\/[^:]+):(\d+):(\d+)/);
                const filePath = fileInfoMatch ? fileInfoMatch[1].split('/').pop() : 'unknown';
                const lineNumber = fileInfoMatch ? fileInfoMatch[2] : 'unknown_line';

                // msg2를 JSON 문자열로 변환 (배열 또는 객체일 때만)
                if(msg2){
                    if (Array.isArray(msg2) || typeof msg2 === 'object') {
                        msg2 = JSON.stringify(msg2, null, 4) + '\n'; // 4칸 들여쓰기 포함
                    }
                } else {
                    msg2 = '';
                } 
                
                
                // 디버깅 정보 출력
                if (obj_this.debergView === 'Yes' || viewType=== 'Yes') {
                    console.log(
                        `%cDebug Log :: %c${msg1}\n%c\n%c${msg2}\n%cLine Info : ${filePath}  ${lineNumber}`,
                        'color: blue; font-weight: bold;', // '디버깅::' 색상
                        'color: green;',                   // 첫 번째 메시지 색상
                        'color: black;',                   // 구분자 색상
                        'color: red;',                     // 두 번째 메시지 색상
                        'color: orange;'                   // 라인 및 파일 정보 색상
                    );
                }
            }

        },


		/*=========================================================================================
		 * 히스토리 등록
		**---------------------------------------------------------------------------------------*/
        historyEvent : function(eq_idx, objTxt, cls ='white'){
            if( MARI.file_uploder.code.isAdmin === true){
                const obj_this    = MARI.file_uploder.code;
                const now         = new Date();
                const hours       = String(now.getHours()).padStart(2, '0');    // 24시간 형식으로 시를 가져오기
                const minutes     = String(now.getMinutes()).padStart(2, '0');  // 분을 가져오기
                const seconds     = String(now.getSeconds()).padStart(2, '0');  // 초를 가져오기
                const currentTime = `${hours}시:${minutes}분:${seconds}초`;       // 원하는 형식으로 시간 문자열 만들기
                const historyAry  = MARI.file_uploder.code.history_ary[eq_idx]; // 이벤트 내용들이 담기는 배열
 
                // 배열이나 객체일 경우 objTxt 출력을 할 수 있게 변경 
                if (Array.isArray(objTxt) || typeof objTxt === 'object') {
                    msgTitle = objTxt[0]+ ' <span class="historySpan">[ open ▼ ]</span>';
                    objTxt   = msgTitle + ' <pre class="historyCont">' + JSON.stringify(objTxt[1], null, 4) + '</pre>'; // 4칸 들여쓰기로 JSON 형식 변환
                }
 
                let lastPushAry = historyAry[historyAry.length-1];
                let pushAryCon  = '<div class="'+cls+'">'+objTxt.replace(/\n/g, '<br>')+'</div>';
                    pushAryCon += '<div class="historyTime">[ '+currentTime+' ]</div>';

                if(lastPushAry != pushAryCon){ // 이전과 같은 상황이 아닐 경우만 넣어준다 안그럼 데이터가 엄청...
                    MARI.file_uploder.code.history_ary[eq_idx].push(pushAryCon);
                }
            }

        },


        selectRangeText : function(spanNode, fileName = '') {
            // Range 객체를 생성하여 선택 영역 설정
            const range = document.createRange(); 
            const textNode = spanNode.firstChild; // span의 첫 번째 자식 노드가 텍스트 노드라고 가정 
            const startIndex = 0; // 파일명 시작 인덱스 
            const endIndex = fileName.length; // 파일명 끝 인덱스 (fileName 길이) 
            // 선택 영역 설정
            range.setStart(textNode, startIndex); // 텍스트 노드의 startIndex 설정
            range.setEnd(textNode, endIndex);     // 텍스트 노드의 endIndex 설정
            // 알러트 컨펌등이 있을 때 포커스가 소실 되므로 여유 시간을 준다
            let timeoutId  = setTimeout(function() { 
                // Selection 객체로 선택 영역 설정
                const selection = window.getSelection();
                selection.removeAllRanges();  // 기존 선택 영역 제거
                selection.addRange(range);    // 새 영역 추가
            },  10); // 페이드 아웃 시간과 기다리는 시간을 합한

        },
 
        beforeName : null, //파일명 변경시 사용되는 바뀌기 전 파일명을 담아둠

        editFileNameAry : [],
		/*=========================================================================================
		 * 파일명을 검사해서 중복된 파일명을 새로운 파일명으로 바꾼다:1
		**---------------------------------------------------------------------------------------*/ 
        validateAndEditFileName : function(event, objType, editType =''){
			let obj_util     = MARI.file_uploder.util;
			let obj_this     = MARI.file_uploder.code; 
            let objLang      = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            let editFileNameAry = MARI.file_uploder.code.editFileNameAry[0];
            let eq_idx       = (editType === 'editEnd') ? editFileNameAry.eq_idx : obj_this.event_eq(event); //사용 가능하게 설정된 업로더에서의 인덱스 
            let loaderMain   = obj_this.loader_main_obj(eq_idx); 
            let li_obj       = obj_this.li_obj(eq_idx); 
            let editIdx      = (editType === 'editEnd') ? editFileNameAry.editIdx : obj_this.click_idx[eq_idx];
            let objType2     = (editType === 'editEnd') ? editFileNameAry.objType : objType;
            let nameDiv      = li_obj[editIdx].querySelector(obj_this.file_name_in_cls);
            let thumbBt      = li_obj[editIdx].querySelector(obj_this.thumb_bt_cls);
            let delBt        = li_obj[editIdx].querySelector(obj_this.del_bt_cls); 
            let evtTgt       = event.target.className;
            let fileIcon     = nameDiv.querySelector('.file_icon'); 
            let nameSpan     = nameDiv.querySelector(obj_this.file_name_cls);
            let fullFileName = obj_util.trim(nameSpan.innerText);
            let matches      = fullFileName.match(/[\\/:*?"<>|]/g); // 걸러야할 특수문자
            let setFileName  = fullFileName.split('.').slice(0, -1).join('.'); // 확장자를 뺀 파일명
            let setFileExt   = fullFileName.split('.').pop(); // 확장자 
            let tempAry      = MARI.file_uploder.code.temp_Ary[eq_idx] || null; // dTa_Ary에 담기 위한 임시 배열 ( 파일 업로드 행위마다 리셋 )
            let dTaAry       = MARI.file_uploder.code.dTa_Ary[eq_idx];          // New,Modify가 담기는 데이터 배열
            let newFile      = dTaAry.new_files.files;                          // New 파일이 담기는 
            let modifyFile   = dTaAry.modify_files;                             // Modify 파일이 담기는
            let modifyLen    = modifyFile.length;
            let newLen       = newFile.length; 
            let newFileName  = ''; 
            let nameAry      = obj_this.fileNameAry[eq_idx];// 현재의 파일명들을 담아서 비교하는데 사용한다
            let aryIdx       = objType2 === 'New' ? editIdx - modifyLen : editIdx;

            // 선택한 파일을 수정할 수 있도록 속성 변경 ( 더블클릭 이후 계속 )
            if(editType === 'editName'){
                // 파일명과 확장자를 분리 템프에 저장
                let tempFileName = fullFileName.split('.').slice(0, -1).join('.'); // 확장자를 뺀 파일명
                let tempFileExt  = fullFileName.split('.').pop(); // 확장자  
                let list_shape   = obj_this.list_shape[eq_idx];  
                if(list_shape === 'shape1' || list_shape === 'shape2' || list_shape === 'shape3' ){
                    nameDiv.querySelector('.file_icon').style.display = 'none';
                }
                thumbBt.style.display = 'none';
                delBt.style.display   = 'none';
                nameDiv.classList.add('edit');
                nameSpan.setAttribute("contenteditable", true); // 데이터 코드 입히기 
                obj_this.beforeName = fullFileName;
                obj_this.fileNameEdit_flag = true;

                // 수정중인 모듈인덱스와 데이터 타입 배열인덱스를 넣어줘서 바탕클릭으로 닫기할때 사용한다
                MARI.file_uploder.code.editFileNameAry[0] = {'eq_idx' : eq_idx, 'objType' : objType2, 'editIdx' : aryIdx, 'fullFileName' : obj_util.trim(nameSpan.innerText)}; //현재 수정중인 곳 인덱스

                // 파일명 작성시 제한된 문자열이면 팝업 레이어를 보여줌
                obj_this.fileNameInputAct(event, eq_idx, editType, objType2, aryIdx, fullFileName);
            }
    
            // 수정모드 이후 그 안에 파일명 변경등을 하거나 벗어 나서 수정모드를 끝낼 때( 바탕등을 클릭해서 벗어날 때 )
            if (editType === 'editEnd') { // editEnd 
                if (nameDiv) {
                    // 파일명과 확장자를 분리 템프에 저장 
                    let tempFileName = obj_this.beforeName.split('.').slice(0, -1).join('.'); // 확장자를 뺀 파일명
                    let tempFileExt  = obj_this.beforeName.split('.').pop(); // 확장자  
 
                    // 파일명 작성시 제한된 문자열이면 팝업 레이어를 보여줌 
                    obj_this.fileNameInputAct(event, eq_idx, editType, objType2, aryIdx, fullFileName);

                    // 히스토리 입력 
                    let getDatas = obj_this.getFileInfo2(eq_idx, objType2, aryIdx, 'All', '72'); // 데이터  
                    let msgAry = ['파일명 변경 [ '+fullFileName +' => '+ newFileName+' ]', getDatas];
                    obj_this.historyEvent(eq_idx, msgAry, 'orange');

                    // 요소 내부의 `.file_icon` 처리
                    if (fileIcon) {
                        fileIcon.removeAttribute('style'); // 인라인 스타일 제거
                    }
                    // 요소 내부의 이름 span 처리
                    if (nameSpan) {
                        nameSpan.removeAttribute('contenteditable');
                    }
                    // 클래스 제거
                    nameDiv.classList.remove('edit');
                    thumbBt.removeAttribute('style'); // 인라인 스타일 제거
                    delBt.removeAttribute('style');   // 인라인 스타일 제거 
                    MARI.file_uploder.code.editFileNameAry[eq_idx] = []; //초기화

                    // 붙여넣기 후 커서 위치 설정
                    const range     = document.createRange();
                    const selection = window.getSelection();
                    if (nameSpan.firstChild) {
                        const textNode = nameSpan.firstChild;  // 첫 번째 자식 노드가 텍스트 노드
                        range.setStart(textNode, 0);           // 텍스트 노드의 첫 번째 글자 위치 설정
                        range.setEnd(textNode, 0);             // 첫 번째 글자 위치까지 선택 범위 설정
                        selection.removeAllRanges();           // 기존 선택 영역 제거
                        selection.addRange(range);             // 새로 생성한 범위 추가하여 커서를 맨 처음에 위치시킴
                    }
 
                    obj_this.fileNameEdit_flag = false;  
                    obj_this.beforeName = null; // 초기화 
                    // 수정중이면 드래그가 되지 않도록 해제
                    obj_this.use_focus_pannel_act[eq_idx] = 'Y'; 
                }
            }

        },


        /**
         * 특수문자 사용시 제한, 중복문자시
        **/ 
        fileNameInputAct : function(event, eq_idx, editType, objType, aryIdx, fullFileName){
			let obj_util     = MARI.file_uploder.util;
			let obj_this     = MARI.file_uploder.code;  
            let objLang      = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            let li_obj       = obj_this.li_obj(eq_idx); 
            let modifyCnt    = obj_this.file_count_return(eq_idx, 'modifyCnt'); // 파일 업로더 서버에 업로드 완료 갯수
            let listIdx      = (objType === 'Add' || objType === 'New') ? modifyCnt+aryIdx :aryIdx;
            let nameDiv      = li_obj[listIdx].querySelector(obj_this.file_name_in_cls); // 단일 요소 선택 
            let nameSpan     = obj_this.getNameSpan(eq_idx, listIdx);
            let tempFileName = obj_this.beforeName.split('.').slice(0, -1).join('.'); // 확장자를 뺀 파일명
            let tempFileExt  = obj_this.beforeName.split('.').pop(); // 확장자   
            let setFileName  = fullFileName.split('.').slice(0, -1).join('.'); // 확장자를 뺀 파일명
            let setFileExt   = fullFileName.split('.').pop(); // 확장자 
            let forbiddenChars = /[\\/:*?"<>|]/g;   // 타이핑이 있을때 마다 검사

            // 에디터된 파일명에 셀렉트
            obj_this.selectRangeText(nameSpan, setFileName); //tempFileName

            nameSpan.addEventListener('input', () => {
                const textContent = nameSpan.textContent;
                const matches = textContent.match(forbiddenChars);

                if (matches) {
                    let altDom    = obj_this.altPopUpLayer();  
                    let altLayer1 = li_obj[listIdx].querySelector('.altPopUpLayer'); 
                    if(!altLayer1){
                        nameDiv.parentElement.insertAdjacentHTML('beforeend', altDom); 
                        let altLayer = li_obj[listIdx].querySelector('.altPopUpLayer'); 
                        let listHt   = parseInt(altLayer.offsetHeight) + 10;
                        altLayer.style.bottom = - listHt + 'px';
                        //alert('사용할 수 없는 문자열이 포함되어 있습니다: ' + matches.join(', '));
                        obj_util.fadeOut(altLayer, 150,1500, 'block','0', 10, function(){ 
                            altLayer.remove();  
                        });
                    }
                    nameSpan.innerText = obj_util.trim(obj_this.beforeName);//tempFileName + '.' + tempFileExt; // 원래 명칭으로 되돌림
                    obj_this.selectRangeText(nameSpan, tempFileName);  
                    return false; // 진행 중단 
                }
            });
 
            // 파일명과 확장자가 잘못되었을 경우의 처리
            if (!fullFileName.includes('.')) {
                //alert('파일명에 확장자가 없습니다. 올바른 파일명을 입력하세요.');
                alert(objLang.txt201);
                nameSpan.innerText = obj_util.trim(obj_this.beforeName);// 원래 명칭으로 되돌림
                obj_this.selectRangeText(nameSpan, tempFileName);  
                return false; // 확장자가 없으면 더 이상 진행하지 않음
            }

            // 확장자가 없거나 두 글자 이하일 경우
            if (!setFileExt || setFileExt.length <= 2) { // 예: 'js' 같은 경우 두 글자
                //alert('올바른 확장자를 입력하세요. 확장자가 올바르지 않습니다.');
                alert(objLang.txt202);
                nameSpan.innerText = obj_util.trim(obj_this.beforeName);// 원래 명칭으로 되돌림
                obj_this.selectRangeText(nameSpan, tempFileName);
                nameSpan.focus(); // 포커스 설정
                return false;
            }

            // 최소 한 글자 이상의 파일명이 입력되었는지 확인
            if (!setFileName || setFileName.length <= 0) {
               // alert('최소 한 글자 이상의 파일명을 입력하세요.'); 
                alert(objLang.txt203);
                nameSpan.innerText = obj_util.trim(obj_this.beforeName);// 원래 명칭으로 되돌림
                obj_this.selectRangeText(nameSpan, tempFileName);
                nameSpan.focus(); // 포커스 설정
                return false;
            }
            
            // 확장자가 존재하고 변경된 경우에만 경고창 표시
            if (tempFileExt && setFileExt && tempFileExt !== setFileExt) {
             // let cfm = confirm(tempFileExt + ' | ' + setFileExt + ' 파일의 확장명을 변경하면 사용할 수 없게 될 수도 있습니다.\n변경하시겠습니까?');
                let cfm = confirm(objLang.txt205(tempFileExt, setFileExt));
                if (!cfm) {
                    nameSpan.innerText = obj_util.trim(obj_this.beforeName);// 원래 명칭으로 되돌림
                    obj_this.selectRangeText(nameSpan, tempFileName);
                    nameSpan.focus(); // 포커스 설정 
                    return false;
                } else {
                    const fileIcon = nameDiv.querySelector('.file_icon');
                    fileIcon.src = '../../multi_uploader/images/file_kind/'+setFileExt; 
                    // 이미지 로드 실패 시 대체 이미지 설정
                    fileIcon.onerror = () => {
                        fileIcon.src = '../../multi_uploader/images/file_kind/unknown.gif'; // 대체 이미지 경로
                    };
                }
            }

            // 파일명이 255자를 초과하는지 확인 ( 확장자 포함 )
            if (fullFileName.length > obj_this.maxFileNameLength) {
                //alert("파일명이 255자를 초과할 수 없습니다.");
                alert(objLang.txt205);
                nameSpan.innerText = obj_util.trim(obj_this.beforeName);// 원래 명칭으로 되돌림
                obj_this.selectRangeText(nameSpan, tempFileName);
                return false;
            }
            
            //에디터 모드 종류시에
            if(editType === 'editEnd'){
                // 파일명 중복 여부에 따른 처리
                let reFileName = obj_this.uniqueFileName(event, eq_idx, objType, aryIdx, fullFileName);
                if( reFileName !== false ){
                    nameSpan.innerText  = obj_util.trim(reFileName);// 받은 이름으로 파일명을 넣는다
                    obj_this.selectRangeText(nameSpan, setFileName);  
                    obj_this.beforeName = reFileName;
                    /**=============================================================
                     * 위의 모든 상황을 건너서 데이터에 이상이 없다면 데이터를 변경 
                     * 원본의 이름은 변경없이 사용되는 데이터의 변경만 있다
                    **------------------------------------------------------------*/
                    let info_Ary = {};
                    info_Ary['dataFileName'] = reFileName; // 바뀐 파일명
                    // info_Ary['name'] = 'fff'+reFileName; 변경된 것을 복사해서 이름을 바꾸는 꼼수식의 복제가 아니라면 파일api의 이름은 변경할 수 없다
                    info_Ary['dataEdit'] = 'dataNameEdit';   // 고치지 않은::Default 고침이 있으면 Edit로 변경
                    obj_this.setFileInfo(event, eq_idx, objType, aryIdx, info_Ary);   // 데이터 셋팅 후 데이터를 리턴
                }
            }

        },
 

        // 파일명이 사용가능한지 검사 
        // 파일 추가시, 파일명 수정시, 파일명 수정완료시 
        uniqueFileName : function(event, eq_idx, objType, aryIdx, fullFileName){
			let obj_util  = MARI.file_uploder.util;
			let obj_this  = MARI.file_uploder.code;
            let objLang   = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            let nameAry = obj_this.fileNameAry[eq_idx];// 현재의 파일명들을 담아서 비교하는데 사용한다  
            let newFileName = null;
            if( nameAry.includes(fullFileName) ){ 
                let reFileName  = obj_util.generateUniqueFileName(fullFileName, nameAry); // 이름을 재 생성한다
                
              //let cfm = confirm('중복된 파일명이 존재합니다\n\n' + fullFileName + '파일명이 존재하므로 \n'+reFileName+'으로 변경합니다'); 
                let cfm = confirm(objLang.txt206(fullFileName, reFileName)); 
                if (cfm) {
                    newFileName = reFileName;// 새 이름으로 
                } else { //취소시 
                    newFileName = false;// obj_util.trim(obj_this.beforeName);// 원래 이름으로 
                }
            } else { // 중복이 아닌
                    newFileName = fullFileName;// 들어온 이름으로 
            }
            
            // 현재의 이름을 배열에 넣어서 대조용으로 사용한다
            obj_this.fileNameAry[eq_idx].push(newFileName);  

            return newFileName;

        },


        // 파일명이 사용가능한지 검사 
        // 파일 추가시, 파일명 수정시, 파일명 수정완료시 
        uniqueFileName22 : function(event, eq_idx, objType, aryIdx, fullFileName){
			let obj_util  = MARI.file_uploder.util;
			let obj_this  = MARI.file_uploder.code;
            let objLang   = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            let li_obj    = obj_this.li_obj(eq_idx);  
            let nameAry   = obj_this.fileNameAry[eq_idx];// 현재의 파일명들을 담아서 비교하는데 사용한다
            let newFileName = null; // fullFileName;
            if( nameAry.includes(fullFileName) ){ 
                let reFileName  = obj_util.generateUniqueFileName(fullFileName, nameAry); // 이름을 재 생성한다
             // let cfm = confirm('중복된 파일명이 존재합니다\n\n' + fullFileName + '파일명이 존재하므로 \n'+reFileName+'으로 변경합니다');  
                let cfm = confirm(objLang.txt206(fullFileName, reFileName));
                if (cfm) {
                    newFileName = reFileName;// 새 이름으로 
                } else { //취소시 
                    newFileName = false;// obj_util.trim(obj_this.beforeName);// 원래 이름으로 
                }
            } else { // 중복이 아닌
                    newFileName = fullFileName;// 들어온 이름으로 
            }
            // 현재의 이름을 배열에 넣어서 대조용으로 사용한다
            obj_this.fileNameAry[eq_idx].push( newFileName);  

            return newFileName;

        },


        // 파일삭제 컨펌등에 사용
        //let confirmed = obj_this.customConfirm('선택한 ' + select_cnt + '개의 파일을 삭제합니다.'); 
        //if (!confirmed) {
        //    return false; // 삭제 취소 처리
        //}
        customConfirm : function(message) {
            // 모달 배경
            const modalOverlay = document.createElement('div');
            modalOverlay.style.position = 'fixed';
            modalOverlay.style.top = '0';
            modalOverlay.style.left = '0';
            modalOverlay.style.width = '100%';
            modalOverlay.style.height = '100%';
            modalOverlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
            modalOverlay.style.display = 'flex';
            modalOverlay.style.alignItems = 'center';
            modalOverlay.style.justifyContent = 'center';
            modalOverlay.style.zIndex = '9999';

            // 모달 내용
            const modalContent = document.createElement('div');
            modalContent.style.backgroundColor = '#fff';
            modalContent.style.padding = '20px';
            modalContent.style.borderRadius = '5px';
            modalContent.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.1)';
            modalContent.innerHTML = `
                <p>${message}</p>
                <button id="confirm-btn">확인</button>
                <button id="cancel-btn">취소</button>
            `;

            // 모달을 배경에 추가
            modalOverlay.appendChild(modalContent);
            document.body.appendChild(modalOverlay);

            // 확인 버튼 클릭 시
            document.getElementById('confirm-btn').onclick = function() {
                document.body.removeChild(modalOverlay); // 모달 제거
                return true; // true 반환
            };

            // 취소 버튼 클릭 시
            document.getElementById('cancel-btn').onclick = function() {
                document.body.removeChild(modalOverlay); // 모달 제거
                return false; // false 반환
            };

        },


        // 미리보기 이미지의 넓이 높이 포지션 설정
        setPositionImg : function (eq_idx, objType ='first'){  
			let obj_util     = MARI.file_uploder.util;
            let obj_this     = MARI.file_uploder.code;  
            let objLang      = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기 
            let viewTypeFlag = obj_this.viewTypeFlag[eq_idx]; // 미리보기창  preview( 미리보기 ),detail( 상세보기 ) 
            let loaderMain   = obj_this.loader_main_obj(eq_idx);

            // 이미지를 비율값에 맞게 크기를 가감 시키고 가운데 중앙에 위치 시킨다 ( 두군데에서 사용해야할 것이라서 따로 뺌 )  
            if(loaderMain.querySelector('.preview_in_div')){

                let viewObj   = loaderMain.querySelectorAll('.preview_in_div');  // 미리보기 개체       
                let firstDiv  = viewObj[0];
                let secondDiv = viewObj[1] || null;
                let resizeWd  = obj_this.getImageRatio(eq_idx, 'resizeWd');        // 이미지 사이즈
                let resizeHt  = obj_this.getImageRatio(eq_idx, 'resizeHt');        // 이미지 사이즈 
                let posLeft   = obj_this.getImageRatio(eq_idx, 'posLeft');         // 이미지 중앙 위치
                let posTop    = obj_this.getImageRatio(eq_idx, 'posTop');          // 이미지 중앙 위치 
                let firstdImg = firstDiv.querySelector('.preview_upload_thumb2');  // 미리보기 이미지
                let verticalRuler = loaderMain ? loaderMain.querySelector('.view_preview .verticalRuler') : null;
                let previewImg = null;
                if(objType =='first'){
                    previewImg = firstDiv.querySelector('.preview_upload_thumb2');  // 미리보기 이미지  
                }
                else
                if(objType =='second'){
                    previewImg = secondDiv.querySelector('.preview_upload_thumb2'); // 미리보기 이미지 
                }

                // 모듈 리사이즈, 미리보기 리사이즈 내용 공유:: 시작  
                if(obj_this.preview_mode[eq_idx] == 'open'){
                    // 미리보기 드래그바 보이기 또는 감추기 활성 여부
                    obj_this.drag_bar_line_dp(event, eq_idx);
                    let previewImg = loaderMain.querySelector('.preview_upload_thumb2'); // 미리보기 이미지
                    if(previewImg){
                        // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 
                        //리사이즈된 리턴된 값을 가지고 아래에서 한번 더 재 측정이 이뤄진다 
                        let preview     = loaderMain.querySelector('.view_preview');
                        let afterImgWd  = preview.offsetWidth - obj_this.PAD;            // 미리보기에서의 이미지 크기 
                        let originalWd    = Number(obj_this.nowImgNaturalWidth[eq_idx]) ;
                        let originalHt    = Number(obj_this.nowImgNaturalHeight[eq_idx]);
                        let imgPercent  = Math.round(afterImgWd / originalWd * 100); // 퍼센트로 바꾼 비율  
                        // 미리보기시 선택된 미리보기용 이미지가 이 곳에서 리사이징 된다 imgView_imgResize
                        let reResize    = obj_this.imgView_imgResize(eq_idx, objType, imgPercent, '1620 Line'); 
                        let imgPercent2 = Math.round(reResize.newWidth / originalWd * 100);    // 리사이즈 이후 반환된 리사이즈 크기 퍼센트 이미지 비율

                        // 미리보기 트랙볼의 위치 업데이트
                        obj_this.imgViewTrackPosition(event, 'viewResize', eq_idx, imgPercent2, '2024 Line'); // 셀렉트내에 퍼센트 표기
                        //// 이미지 확대,축소 버튼의 모양 변경
                        //obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent2);
                        
                    }// end if 
                }// end if 
                // 모듈 리사이즈, 미리보기 리사이즈 내용 공유:: 끝
            }// end if 

        },// setPositionImg


        /**
         * 이미지 비율에 따른 넓이 높이 좌측위치 높이 위치 현재의 비율등을 리턴
         * // 다시 한번 검수할 것
         * *===========================================
         *   이미지 리사이징 공식:
         *   가로 비율 = (변경된 가로 크기 / 원본 가로 크기) * 100
         *   세로 비율 = (변경된 세로 크기 / 원본 세로 크기) * 100
         *   평균 축소 비율 = (가로 비율 + 세로 비율) / 2
        */
        getImageRatio : function(eq_idx, objType = '') {
            let obj_this     = MARI.file_uploder.code;
            let objLang      = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            let loaderMain   = obj_this.loader_main_obj(eq_idx); 
            let preview_mode = obj_this.preview_mode[eq_idx];
            let preview      = loaderMain.querySelector('.view_preview');
            let padding      = obj_this.PAD;
            let container    = loaderMain.querySelector('.file_loader .view_preview');
            let previewImg   = loaderMain.querySelector('.preview_upload_thumb2'); 
            let originalWd   = obj_this.nowImgNaturalWidth[eq_idx]  || 184; // 원본 이미지 크기 
            let originalHt   = obj_this.nowImgNaturalHeight[eq_idx] || 160; // 원본 이미지 크기 
            let afterImgWd   = preview.offsetWidth  - padding;       // 미리보기 공간을 이용해서 리사이즈의 넓이로 사용::기준값으로 사용
            let afterImgHt   = preview.offsetHeight - padding;       // 미리보기 공간을 이용해서 리사이즈의 높이로 사용
            let resized      = obj_this.resizeImage(originalWd, originalHt, afterImgWd); // 넓이 기준으로 리사이징 체크::리사이즈된 넓이는 공간을 기준으로
            let resizeWd     = resized.width;  //  변경된 넓이
            let resizeHt     = resized.height; //  변경된 높이 
            let widthRatio  = (resizeWd / originalWd) * 100;
            let heightRatio = (resizeHt / originalHt) * 100;
            let ratio       = ((widthRatio + heightRatio) / 2).toFixed(2); // 원본이미지와 현재 이미지 크기를 통한 비율  
            let wdRatio     = (previewImg.width / originalWd)*100;         // 원본이미지와 현재 이미지 크기를 통한 비율  아래는 100을 곱하고 여기는 소숫점 상태
            // 위치 계산
            let conWd       = container.offsetWidth   - (2 * padding);
            let conHt       = container.offsetHeight  - (2 * padding);
            const posLeft   = ( (conWd - resizeWd) / 2 ) + ( padding / 2 );
            const posTop    = ( (conHt - resizeHt) / 2 ) + ( padding / 2 );
            // 반환 값 선택
            const values = { 
                        'resizeWd':resizeWd, 'resizeHt':resizeHt, 'posLeft':posLeft, 
                        'posTop':posTop, 'ratio':ratio, 'wdRatio':wdRatio};

            return values[objType] ?? null;

        }, 


        getImageRatio2 : function(eq_idx, objType = '') {
            let obj_this     = MARI.file_uploder.code;
            let objLang      = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            let loaderMain   = obj_this.loader_main_obj(eq_idx); 
            let preview_mode = obj_this.preview_mode[eq_idx];
            let preview      = loaderMain.querySelector('.view_preview');
            let container    = loaderMain.querySelector('.file_loader .view_preview');
            let previewImg   = loaderMain.querySelector('.preview_upload_thumb2');
            let file_main    = loaderMain.querySelector(obj_this.file_main_cls);
            let padding      = obj_this.PAD;//20; 

            if(!previewImg) return false;

            // 컨테이너 크기 계산
            let conWd  = container.offsetWidth   - (2 * padding);
            let conHt  = container.offsetHeight  - (2 * padding);
            let mainHt = file_main.offsetHeight  - (2 * padding); 

            // 이미지 크기 및 원본 크기
            let beforeImgWd  = obj_this.nowImgNaturalWidth[eq_idx];   // 원본 이미지 크기 
            let beforeImgHt  = obj_this.nowImgNaturalHeight[eq_idx];  // 원본 이미지 크기 
            let afterImgWd   = previewImg.offsetWidth;                // 미리보기에서의 이미지 크기
            let afterImgHt   = previewImg.offsetHeight;
            let beforeWd     = obj_this.resize_viewWidth[eq_idx];     // 미리보기 공간의 크기
            let beforeHt     = obj_this.resize_viewHeight[eq_idx];
            let calcWidth    = (preview_mode === 'open') ? parseInt(preview.offsetWidth) : parseInt(obj_this.viewrDefaultWidth); 
            let afterZoneWd  = calcWidth - (2 * padding);   // 이미지가 자리잡은 공간
            let aspectRatio  = afterZoneWd / beforeImgWd;   // 크기 비율 계산 ( 공간을 넓히고 줄이는데 이를 통해서 이미지 비율에 사용 )
            let afterViewWd  = parseInt(preview.offsetWidth);
            let beforeViewWd = beforeWd;

            // mp3 컨트롤부 크기 조정
            if (obj_this.click_extention === 'mp3') {
                let newImgHt = beforeImgHt - 100; // 새로운 높이 
                let newImgWd = (newImgHt / beforeImgHt) * beforeImgWd;
                beforeImgHt  = newImgHt;  
                beforeImgWd  = newImgWd;
            }

            // 새로운 크기 계산
            let resizeWd      = beforeImgWd * aspectRatio;
            let resizeHt      = beforeImgHt * aspectRatio;
            let originalRatio = afterImgWd / beforeImgWd; // 이전, 현재 이미지를 통한 비율 계산 
            let viewRatio     = afterViewWd / beforeViewWd; // 이전, 현재 이미지를 통한 비율 계산

            // 미리보기 영역이 최소 사이즈보다 작거나 닫혀진 상태라면
            if( conWd < parseInt(obj_this.min_preview_wd) ){
                conWd = parseInt(obj_this.min_preview_wd) - (2 * padding);
                conHt = parseInt(mainHt);
            }

            // 컨테이너 크기에 맞춰 조정
            if (resizeWd > conWd) {
                resizeWd = conWd;
                resizeHt = resizeWd * (beforeImgHt / beforeImgWd);
            }

            if (resizeHt > conHt) {
                resizeHt = conHt;
                resizeWd = resizeHt * (beforeImgWd / beforeImgHt);
            }

            // 최소 크기 제한
            resizeWd = Math.max(resizeWd, 10) + obj_this.PAD;
            resizeHt = Math.max(resizeHt, 10) + obj_this.PAD;//0

            let newSize = obj_this.resizeImage(beforeImgWd, beforeImgHt, resizeWd);
            newWidth    = newSize.width;
            newHeight   = newSize.height; 
            resizeWd    = newWidth;
            resizeHt    = newHeight; 
 
            // 위치 계산
            const posLeft = ( (conWd - resizeWd) / 2 ) + ( padding / 2 );
            const posTop  = ( (conHt - resizeHt) / 2 ) + ( padding / 2 );

            // 반환 값 선택
            const values = { 
                        'resizeWd':resizeWd, 'resizeHt':resizeHt, 'posLeft':posLeft, 
                        'posTop':posTop, 'ratio':originalRatio, 'viewRatio':aspectRatio};
     
            return values[objType] ?? null;

        },


        imgControllerAct : function(event, eq_idx, target_idx) { 
            const obj_this        = MARI.file_uploder.code; 
            const objLang         = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
			const obj_util        = MARI.file_uploder.util;
            //let eq_idx          = obj_this.eq_idx; 
            let select_cnt        = obj_this.selectCnt(eq_idx);  // 드래그 선택중인 갯수 리턴
            let wheelEvtAdded     = false; // wheel 이벤트 중복 방지 플래그를 전역에서 선언  
            let isDragging1       = false; // 드래그 상태를 확인하는 변수
            let isDragging2       = false; // 드래그 상태를 확인하는 변수 
            let isDragging3       = false; // 드래그 상태를 확인하는 변수 :: 가이드라인 
            let isDragging4       = false; // 드래그 상태를 확인하는 변수 :: 가이드라인 
            let isMouseDown       = false; // 마우스 다운 상태를 추적
            let mouseMoveListener = null;
            let mouseUpListener   = null;
            let mouseDownListener = null;
            let timeoutId         = obj_this.set_time_var3;
            let intervalId        = obj_this.set_time_var4;
            let startX, startY;
            let lineLeft,lineTop;
            let g_startX, g_startY;
            let initialX, initialY;
            let nowWidth, nowHeight;  //현재 이미지 사이즈 넓이, 높이

            // "네비게이션 줌(panning navigation)" 또는 **"미니맵 이동(minimap panning)"
            // 미리보기 이미지 네비게이션:: 보이거나 감추기
            function resizeNaviImage(maxSize) { 
                let loaderMain            = obj_this.loader_main_obj(eq_idx);
                let imgViewNavi           = loaderMain.querySelector('.imgViewNavi'); // 네비 이미지 담긴 
                let naviImg               = loaderMain.querySelector('.naviImg');     // 네비 이미지  
                let originalWd            = obj_this.nowImgNaturalWidth[eq_idx];      // 원본 이미지 크기
                let originalHt            = obj_this.nowImgNaturalHeight[eq_idx]; 
                let imgViewNaviResize     = obj_util.resizeToFit(originalWd, originalHt, maxSize); 
                imgViewNavi.style.display = 'none';
                imgViewNavi.style.width   = imgViewNaviResize.width  + 4 +'px';
                imgViewNavi.style.height  = imgViewNaviResize.height + 4 +'px'; 
                naviImg.style.width       = imgViewNaviResize.width  + 'px';
                naviImg.style.height      = imgViewNaviResize.height + 'px';

            } 
            resizeNaviImage(116); // 감싼 크기까지 120

            // 게이지 이동에 따른 이미지 크기 변환                
            function valueSpanVal(event){
                // 비율을 계산하여 newValue를 구함 
                if(obj_this.drag_flag || obj_this.selectCnt2 > 1) return false;
                let eq_idx       =  obj_this.eq_idx; 
                if(eq_idx === null) return false;
                let loaderMain   = obj_this.loader_main_obj(eq_idx);
                let selectInput  = loaderMain ? loaderMain.querySelector('.selectInput') : null;
                if(selectInput === null) return false;
                let slider       = loaderMain.querySelector('.slider'); // 슬라이더
                let handle       = slider.querySelector('.slider-handle'); 
                let valueSpan    = loaderMain.querySelector('.slider-value'); // 슬라이더 
                let minValue     = obj_this.imgMinZoomValue; // 슬라이더의 최소값
                let maxValue     = obj_this.imgMaxZoomValue; // 슬라이더의 최대값  
                const rect       = slider.getBoundingClientRect();
                const trackWidth = slider.offsetWidth; // 슬라이더의 전체 너비
                let offsetX      = event.clientX - rect.left; // 마우스 X 위치 
                const percentage = offsetX / trackWidth; // 0 ~ 1 사이의 비율
                let newValue     = Math.round(percentage * (maxValue - minValue) + minValue); // 1 ~ 800 범위로 변환
                newValue         = Math.max(minValue, Math.min(newValue, maxValue)); // 최소, 최대값 제약

                if(valueSpan)
                valueSpan.textContent = newValue + '%'; // 슬라이더 값 업데이트  
                if(selectInput)
                selectInput.value     = newValue + '%'; // 셀렉트 값 업데이트
 
                return newValue;

            }//end func valueSpanVal


            function selectInputAct(){
                if(obj_this.drag_flag || obj_this.selectCnt2 > 1) return false;
                let eq_idx        =  obj_this.eq_idx; 
                if(eq_idx === null) return false;
                let loaderMain    = obj_this.loader_main_obj(eq_idx);
                let selectInput   = loaderMain ? loaderMain.querySelector('.selectInput') : null;  
                if(selectInput === null) return false;
                let inputValue    = selectInput.value.trim(); // 인풋에 들어간 값
                let selectMenu    = loaderMain ? loaderMain.querySelector('.selectMenu') : null;  
                if(selectMenu === null) return false;
                let options       = Array.from(selectMenu.options); 
                let matchedOption = options.find(option => option.value === inputValue); 
                let onlyNumbers   = inputValue.replace(/\D/g, ""); // 숫자가 아닌 문자를 모두 제거 
                let isValid       = /^\d+%$/.test(inputValue);
                let optIdx        = selectMenu.selectedIndex;
                let originalWd    = obj_this.nowImgNaturalWidth[eq_idx];       // 원본 이미지 크기
                let originalHt    = obj_this.nowImgNaturalHeight[eq_idx]; 
                let valueSpan     = loaderMain.querySelector('.slider-value'); // 슬라이더  

                if (matchedOption) {
                    selectMenu.selectedIndex = optIdx + 1;
                    selectMenu.value = inputValue; // 일치하면 선택  
                } else {
                    selectMenu.selectedIndex = -1; // 일치하지 않으면 선택 해제
                    // 내용이 올바르지 않다면 해당 넓이에 맞는 내용을 넣기 위해 슬라이더 팝업에 기록된 값을 가져다 쓴다
                    if(!isValid){
                        let reValue       = valueSpan.innerText.trim();
                        let onlyNumbers2  = reValue.replace(/\D/g, ""); // 숫자가 아닌 문자를 모두 제거 
                        selectInput.value = reValue;
                        onlyNumbers = onlyNumbers2;
                    }
                }

                if(onlyNumbers < 1 )   onlyNumbers = 1;
                if(onlyNumbers > 800 ) onlyNumbers = 800;

                if(onlyNumbers >=1 && onlyNumbers <= 800){ 
                    let imgPercent2 = onlyNumbers; 
                    // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 리사이즈된 리턴된 값을 가지고 아래에서
                    // 한번 더 재 측정이 이뤄진다
                    // 히스토리 입력
                    obj_this.historyEvent(eq_idx,  '직접 기재로 이미지 크기 변경 : '+onlyNumbers+'%');
                    let reResize    = obj_this.imgView_imgResize(eq_idx, 'btn', imgPercent2, '2009 Line'); 
                    let imgRatio3   = reResize.newWidth / originalWd; // 리사이즈 이후 반환된 리사이즈 크기로 비율을 측정
                    let imgPercent3 = Math.round(imgRatio3 * 100);    // 퍼센트 이미지 비율   

                    // 미리보기 트랙볼의 위치 업데이트
                    obj_this.imgViewTrackPosition(event, 'btn', eq_idx, imgPercent3, '2014 Line'); 
                    // 이미지 확대,축소 버튼의 모양 변경
                    obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent3);
                    selectMenu.value = onlyNumbers; // 일치하면 선택 
                }

                //포커스 해제
                selectInput.blur();
            }// end func selectInputAct 

            // 이벤트 리스너의 등록과 메모리 관리를 위해 리스너 해제를 위해서 아래와 같은 형태를 사용해 볼 것   
            // 이벤트 리스너 참조 저장
            function isDraggingMouseMove(event) {  
                if ( !(event.target.className === 'preview_upload_thumb2'|| 
                       event.target.className === 'slider-handle' ||
                       event.target.className === 'helperDiv')) {
                    return false;
                }

                if(obj_this.drag_flag || obj_this.selectCnt2 > 1) return false;

                let eq_idx       =  obj_this.eq_idx;
                if(eq_idx === null) return false; 
                let loaderMain    = obj_this.loader_main_obj(eq_idx);
                let originalWd    = obj_this.nowImgNaturalWidth[eq_idx];       // 원본 이미지 크기
                let originalHt    = obj_this.nowImgNaturalHeight[eq_idx]; 

                // 이미지 확대,축소를 위한 슬라이더 게이지 드래그가 있을 때
                if (isDragging1) {
                    let imgPercent = valueSpanVal(event); 
                    // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 리사이즈된 리턴된 값을 가지고 아래에서
                    // 한번 더 재 측정이 이뤄진다  
                    let reResize    = obj_this.imgView_imgResize(eq_idx, 'track', imgPercent, '1964 Line'); 
                    let imgRatio2   = reResize.newWidth / originalWd; // 리사이즈 이후 반환된 리사이즈 크기로 비율을 측정
                    let imgPercent2 = Math.round(imgRatio2 * 100);    // 퍼센트 이미지 비율  
                    // 미리보기 트랙볼의 위치 업데이트
                    obj_this.imgViewTrackPosition(event, 'track', eq_idx, imgPercent2, '1968 Line'); 
                    // 이미지 확대,축소 버튼의 모양 변경
                    obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent2);  
                }
                // 미리보기 이미지에서 이미지 드래그가 있었을 대
                else
                if (isDragging2) { 
                    let previewImg = loaderMain.querySelector('.preview_upload_thumb2'); 
                    let deltaX  = event.clientX - startX;
                    let deltaY  = event.clientY - startY;
                    let newLeft = initialX + deltaX;
                    let newTop  = initialY + deltaY;
                    let preview = loaderMain.querySelector('.view_preview');
                    let viewWd  = preview.offsetWidth;
                    let viewHt  = preview.offsetHeight;

                    // 중심 좌표 기반으로 위치 조정
                    let posL = deltaX + initialX;
                    let posT = deltaY + initialY;
 
                    // 이미지의 크기가 공간을 넘어서서 드래그가 필요하다면 좌우 경계를 넘어서지 않도록
                    if(nowWidth > viewWd &&  nowHeight > viewHt){  
                        // 좌우 경계
                        if (posL > 0) posL = 10; // 왼쪽 경계::패딩20일 경우 0
                        if (viewWd - obj_this.PAD - nowWidth > posL) {
                            posL = viewWd - obj_this.PAD - nowWidth ; // 오른쪽 경계
                        }
                        // 상하 경계
                        if (posT > 0) posT = 10; // 윗쪽 경계::패딩20일 경우 0
                        if (viewHt - obj_this.PAD - nowHeight > posT) {
                            posT = viewHt - obj_this.PAD - nowHeight; // 아랫쪽 경계
                        }
                    }

                    if(nowWidth > viewWd &&  nowHeight < viewHt){  
                        // 좌우 경계
                        if (posL > 0) posL = 10; // 왼쪽 경계::패딩20일 경우 0
                        if (viewWd - obj_this.PAD - nowWidth > posL) {
                            posL = viewWd - obj_this.PAD - nowWidth ; // 오른쪽 경계
                        }
                        // 상하 경계
                        if (posT < 10) posT = 10; // 윗쪽 경계::패딩20일 경우 0
                        if (viewHt - obj_this.PAD - nowHeight < posT) {
                            posT = viewHt - obj_this.PAD - nowHeight; // 아랫쪽 경계
                        } 
                    }

                    if(nowWidth < viewWd &&  nowHeight > viewHt){  
                        // 좌우 경계
                        if (posL < 0) posL = 10; // 왼쪽 경계::패딩20일 경우 0
                        if (viewWd - obj_this.PAD - nowWidth < posL) {
                            posL = viewWd - obj_this.PAD - nowWidth ; // 오른쪽 경계
                        } 
                        // 상하 경계
                        if (posT > 10) posT = 10; // 윗쪽 경계::패딩20일 경우 0
                        if (viewHt - obj_this.PAD - nowHeight > posT) {
                            posT = viewHt - obj_this.PAD - nowHeight; // 아랫쪽 경계
                        }
                    }

                    // 이미지 움직임 플래그 
                    obj_this.imgResizeMovingFlag = true;
                    // 이미지 위치 설정
                    previewImg.removeAttribute('style');
                    previewImg.style.left   = posL + 'px';
                    previewImg.style.top    = posT + 'px';
                    previewImg.style.width  = nowWidth + 'px';
                    previewImg.style.height = nowHeight + 'px';
                }

            }// end func isDraggingMouseMove

            /*===================================
             * 미리보기 마우스 오버시 이벤트
            **---------------------------------*/ 
            function previewImgHandleMouseOver(event) {
                if(obj_this.drag_flag || obj_this.selectCnt2 > 1) return false;

                if (!['view_preview', 'preview_upload_thumb2', 'selectInput', 'selectMenu', 
                      'slider-handle', 'naviImg', 'view_typeBt', 'view_typeBt on', 
                      'imgCtrPannel', 'imgCtrL_on', 'imgCtrR_on']
                      .some(cls => event.target.classList.contains(cls))) {

                    return false;
                }

                // view_preview 요소에 마우스가 들어갔을 때
                if (event.target.className === 'view_preview') { 
                    let eq_idx        =  obj_this.eq_idx;
                    if(eq_idx === null) return false;
                    let loaderMain    = obj_this.loader_main_obj(eq_idx); 
                    let ctrlPannel    = loaderMain ? loaderMain.querySelector('.view_preview .preview_img_control') : null;
                    let verticalRuler = loaderMain ? loaderMain.querySelector('.view_preview .verticalRuler') : null; 
                    let verticalGuide = loaderMain ? loaderMain.querySelector('.view_preview .verticalGuide') : null;  
                    if (ctrlPannel && ctrlPannel.style.display === 'none' ) {
                        verticalRuler.classList.add('hov');
                        verticalGuide.classList.add('hov');
                    }
                }

                // 미리보기 이미지 위에서 마우스 휠로 크기 키우거나 줄이기
                if (event.target.className === 'preview_upload_thumb2' && !wheelEvtAdded) {

                    // 휠 올림 내림으로 이미지 확대 축소,  휠 이벤트 리스너 추가, passive 옵션을 false로 설정
                    document.addEventListener('wheel', function(event) {
                        let eq_idx         =  obj_this.eq_idx;
                        if(eq_idx === null) return false;
                        if(eq_idx === null) return false; 
                        let loaderMain     = obj_this.loader_main_obj(eq_idx);
                        let preview        = loaderMain.querySelector('.view_preview');          // 미리보기 공간 
                        let previewImg     = loaderMain.querySelector('.preview_upload_thumb2'); // 미리보기 이미지   
                        let viewWd         = preview.offsetWidth;
                        let viewHt         = preview.offsetHeight;
                        let scale          = 1;                                    // 초기 이미지 크기 설정
                        let scaleFactor    = 0.01;                                 // 확대/축소 정도 

                        if(previewImg === null) return false; 
                        
                        let nowImgWidth  = previewImg.offsetWidth;  // 현재 너비
                        let nowImgHeight = previewImg.offsetHeight; // 현재 높이
                        if(nowImgWidth > viewWd || nowImgHeight > viewHt){
                            previewImg.style.cursor = 'grab';
                        } else {
                            previewImg.style.cursor = 'default';
                        }

                        const validClasses = [
                            'file_info', 'file_view_dp', 'view_preview', 
                            'preview_in_div', 'preview_upload_thumb', 'preview_upload_thumb2'
                        ];

                        // 이벤트 발생한 대상이 특정 클래스 중 하나인지 확인
                        if (validClasses.includes(event.target.className)) {
                            event.preventDefault(); // 기본 스크롤 동작 방지
                            let imgViewNavi  = loaderMain.querySelector('.imgViewNavi'); // 미리보기 이미지  

                            // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 
                            //리사이즈된 리턴된 값을 가지고 아래에서 한번 더 재 측정이 이뤄진다  
                            let afterImgWd   = preview.offsetWidth - obj_this.PAD;         // 미리보기에서의 이미지 크기 
                            let originalWd   = obj_this.nowImgNaturalWidth[eq_idx];       // 원본 이미지 크기
                            let originalHt   = obj_this.nowImgNaturalHeight[eq_idx];
                            let imgPercent   = Math.round(afterImgWd / originalWd * 100); // 퍼센트로 바꾼 비율  
                            let reResize     = obj_this.imgView_imgResize(eq_idx, 'wheelResize', imgPercent, '1876 Line');
                            let imgPercent2  = Math.round(reResize.newWidth / originalWd * 100); // 리사이즈 이후 반환된 리사이즈 크기 퍼센트 이미지 비율
                            
                            // 미리보기 트랙볼의 위치 업데이트
                            obj_this.imgViewTrackPosition(event, 'viewResize', eq_idx, imgPercent2, '1879 Line'); 
                            // 이미지 확대,축소 버튼의 모양 변경
                            obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent2);

                            if(nowImgWidth > viewWd || nowImgHeight > viewHt){
                                previewImg.style.cursor = 'grab';
                            } else {
                                previewImg.style.cursor = 'default';
                            }
 
                        }
                    }, { passive: false });
                    wheelEvtAdded = true; // wheel 이벤트 중복 방지 플래그 설정
                } 

                if (( event.target.className === 'selectInput' || event.target.className === 'selectMenu' )) {
                    // 미리보기 이미지 드래그를 위한 마우스 다운시
                    let eq_idx      =  obj_this.eq_idx;
                    if(eq_idx === null) return false;
                    let loaderMain  = obj_this.loader_main_obj(eq_idx);
                    // 하단 이미지 미리보기 셀렉트 박스에 대한 기능  
                    let selectInput = loaderMain ? loaderMain.querySelector('.selectInput') : null;
                    if(selectInput === null) return false;
                    // 더블 클릭시 내용 전체 선택
                    selectInput.addEventListener('dblclick', () => {
                        selectInput.select(); 
                    });
                }

                if (event.target.className === 'selectInput' || event.target.className === 'selectMenu') {
                    let eq_idx      =  obj_this.eq_idx;
                    if(eq_idx === null) return false;
                    let loaderMain  = obj_this.loader_main_obj(eq_idx);
                    let originalWd  = obj_this.nowImgNaturalWidth[eq_idx];   // 원본 이미지 크기
                    let originalHt  = obj_this.nowImgNaturalHeight[eq_idx]; 
                    // 하단 이미지 미리보기 셀렉트 박스에 대한 기능  
                    let selectInput = loaderMain ? loaderMain.querySelector('.selectInput') : null;
                    let selectMenu  = loaderMain ? loaderMain.querySelector('.selectMenu') : null;  
                    if(selectInput === null) return false;
                    if(selectMenu  === null) return false;

                    if(selectInput && selectMenu){

                        // 입력 박스에서 포커스를 벗어날 때 처리
                        selectInput.addEventListener('blur',  (event) => {
                            // 셀렉트 박스와 인풋박스를 통한 리사이징 처리
                            selectInputAct();
                           // alert('1');
                        });
                        
                        selectInput.addEventListener('keydown', (event) => { 
                            if (event.key === 'Enter') { // 엔터 키인지 확인
                                event.preventDefault();  // 엔터키에 의한 페이지 전환 금지
                                // 셀렉트 박스와 인풋박스를 통한 리사이징 처리
                                selectInputAct();
                            }
                        });

                        // 옵션 변경시
                        selectMenu.addEventListener('change', function () {
                            // 선택된 옵션의 값을 input 필드에 설정
                            selectInput.value = selectMenu.value; 
                            let imgPercent2 = selectMenu.value; 
                            // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 리사이즈된 리턴된 값을 가지고 아래에서
                            // 한번 더 재 측정이 이뤄진다  
                            let reResize    = obj_this.imgView_imgResize(eq_idx, 'btn', imgPercent2, '2113 Line'); 
                            let imgRatio3   = reResize.newWidth / originalWd; // 리사이즈 이후 반환된 리사이즈 크기로 비율을 측정
                            let imgPercent3 = Math.round(imgRatio3 * 100);    // 퍼센트 이미지 비율

                            // 미리보기 트랙볼의 위치 업데이트
                            obj_this.imgViewTrackPosition(event, 'btn', eq_idx, imgPercent3, '2117 Line'); 
                            // 이미지 확대,축소 버튼의 모양 변경
                            obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent3); 
                        });
                    }
                }
                 
            } // end previewImgHandleMouseOver(event)

            /*===================================
             * 마우스 휠 이벤트
            **---------------------------------*/  
            //이미지 줌::미리보기 이미지 이동 제한 및 네비게이션 제어 
            function previewImgHandleMouseWheel(event) {
                
                // 휠 올림 내림으로 이미지 확대 축소,  휠 이벤트 리스너 추가, passive 옵션을 false로 설정 
                const validClasses = [
                    'selectInput', 'selectMenu', 
                    'imgRatioSelectMenu'
                ];

                let eq_idx      = obj_this.eq_idx;
                let loaderMain  = obj_this.loader_main_obj(eq_idx);
                let selectInput = loaderMain ? loaderMain.querySelector('.selectInput') : null;
                let selectMenu  = loaderMain ? loaderMain.querySelector('.selectMenu') : null;  
                // 이벤트 발생한 대상이 특정 클래스 중 하나인지 확인
                if (validClasses.includes(event.target.className)) {
                    event.preventDefault(); // 기본 스크롤 동작 방지

                    let optIdx    = selectMenu.selectedIndex;
                    let optLen    = selectMenu.options.length; 
                    let target    = parseInt(selectInput.value.replace(/\D/g, ''), 10);       // 현재의 인풋값에서 % 제거 후 숫자만 추출
                    let selectNum = [800, 700, 600, 500, 400, 300, 200, 100, 75, 50, 25, 10]; // 셀렉트 박스의 값 
                    let schIdx    = null;

                    // 현재 인풋값에 셀렉트 박스의 다음 사용될 인덱스 찾기
                    if (event.deltaY < 0) { 
                        let filtered = selectNum.filter(num => num > target); // 타겟값 보다 큰 값만 필터링 
                        let closest  = Math.min(...filtered); // 필터링된 값 중 가장 작은 값을 찾기 
                        schIdx       = selectNum.indexOf(closest); // 인덱스 찾기
                    } else {
                        let filtered = selectNum.filter(num => num < target); // 타겟값 보다 작은 값만 필터링 
                        let closest  = Math.max(...filtered); // 필터링된 값 중 가장 큰 값을 찾기 
                        schIdx       = selectNum.indexOf(closest); // 인덱스 찾기   
                    }

                    // 휠 움직임이 있어서 값이 들어왔다면 새로운 값 설정
                    if (schIdx !== null) {
                        selectInput.value = schIdx + '%';
                        selectMenu.selectedIndex = schIdx;
                    }

                    // 선택된 옵션을 입력 박스에 표시 :: 마우스 휠로 크기 변경시에도 셀렉트 선택된 이후라 값을  찾아 넣어줌
                    if(selectMenu.selectedIndex > 0){
                        selectInput.value = selectMenu.options[selectMenu.selectedIndex].text;
                    }

                    selectInputAct();     // 셀렉트 박스와 인풋박스를 통한 리사이징 처리 
                    selectInput.select(); // 휠을 움직이는 동안에도 셀렉트가 풀려 커서가 꿈뻑이지 않도록
                }
 
            } // end previewImgHandleMouseWheel
 
            /*===================================
             * 미리보기 슬라이더,이미지 이동 마우스 다운시 이벤트
            **---------------------------------*/ 
            function previewImgHandleMouseDown(event) {

                if (event.target.className === 'slider-handle') {
                    let eq_idx = obj_this.eq_idx;
                    if (eq_idx === null) return false;
                    
                    let loaderMain = obj_this.loader_main_obj(eq_idx);
                    let selectInput = loaderMain ? loaderMain.querySelector('.selectInput') : null;
                    let selectMenu = loaderMain ? loaderMain.querySelector('.selectMenu') : null;
                    let valueSpan = loaderMain.querySelector('.slider-value');
                    let ctrlPannel = loaderMain ? loaderMain.querySelector('.view_preview .preview_img_control') : null;
                    let verticalRuler = loaderMain ? loaderMain.querySelector('.view_preview .verticalRuler') : null;
                    let verticalGuide = loaderMain ? loaderMain.querySelector('.view_preview .verticalGuide') : null; 
                    let inputValue = selectInput.value;
                    selectMenu.selectedIndex = -1;
                    for (let i = 0; i < selectMenu.options.length; i++) {
                        if (selectMenu.options[i].text.trim() === inputValue.trim()) {
                            selectMenu.selectedIndex = i;
                            break;
                        }
                    }

                    isDragging1 = true;
                    valueSpanVal(event);
                    obj_util.fadeIn(valueSpan, 200);
                    obj_this.helperDiv_create(event, 'pointer'); 

                    if (ctrlPannel) {
                        ctrlPannel.style.display = 'block';
                        ctrlPannel.style.opacity = '1';
                        verticalRuler.classList.add('hov');
                        verticalGuide.classList.add('hov');
                    }
                }
  
                if (event.target.className === 'preview_upload_thumb2'|| event.target.className === 'slider-handle') {
                    let eq_idx = obj_this.eq_idx;
                    if (eq_idx === null) return false;
                    let loaderMain = obj_this.loader_main_obj(eq_idx);
                    let previewImg = loaderMain.querySelector('.preview_upload_thumb2');
                    let view_preview = loaderMain.querySelector('.view_preview');
                    let viewWd = view_preview.offsetWidth;
                    let viewHt = view_preview.offsetHeight;

                    startX = event.clientX;
                    startY = event.clientY;
                    initialX = parseInt(previewImg.style.left || 0, 10);
                    initialY = parseInt(previewImg.style.top || 0, 10);
                    nowWidth = previewImg.offsetWidth;
                    nowHeight = previewImg.offsetHeight;

                    if (nowWidth > viewWd - obj_this.PAD || nowHeight > viewHt - obj_this.PAD) {
                        isDragging2 = true;
                        obj_this.helperDiv_create(event, 'grabbing');
                        event.preventDefault();
                    }
                }
                
                // 안내선 ( 십자선 ) 
                if (event.target.classList.contains('verticalGuide') || event.target.classList.contains('horizontalGuide')) {
                    let eq_idx = obj_this.eq_idx;
                    if (eq_idx === null) return false;
                    let loaderMain      = obj_this.loader_main_obj(eq_idx); 
                    let front_panel     = loaderMain.querySelector(obj_this.front_panel_cls); // 프론트 판넬
                    let frontPanelDiv   = document.createElement('div');  
                    let file_zone_obj   = loaderMain.querySelector(obj_this.file_zone_cls);   // 기능별 div가 들어가는
                    let verticalGuide   = loaderMain ? loaderMain.querySelector('.view_preview .verticalGuide') : null; 
                    let horizontalGuide = loaderMain ? loaderMain.querySelector('.view_preview .horizontalGuide') : null; 
                    let cursorType = null;

                    if(event.target.classList.contains('verticalGuide')){ // 아래로 내려 뻗은 수직의 라인( | ) x만 움직인다
                        g_startX    = event.clientX - verticalGuide.offsetLeft;
                        lineLeft    = verticalGuide.offsetLeft; 
                        g_startY    = 0;
                        cursorType  = 'col-resize';
                        isDragging3 = true; 
                    }
                    if(event.target.classList.contains('horizontalGuide')){ // 옆으로 누운 수평의 라인( - ) y만 움직인다
                        g_startX    = 0;
                        lineTop     = horizontalGuide.offsetTop;
                        g_startY    = event.clientY - horizontalGuide.offsetTop;
                        cursorType  = 'row-resize';
                        isDragging4 = true; 
                    } 
                    
                    // 헬퍼 div와 프론트 판넬 생성으로 
                    obj_this.helperDiv_create(event, cursorType); 
                    if (!front_panel) {
                        frontPanelDiv.className = 'front_panel';
                        file_zone_obj.appendChild(frontPanelDiv);
                        frontPanelDiv.style.display = 'block';
                    }
                    else{
                        front_panel.style.display = 'block';
                    }
                }

            }// end previewImgHandleMouseDown
 
            /*===================================
             * 마우스 업 이벤트
            **---------------------------------*/  
            //이미지 줌::미리보기 이미지 이동 제한 및 네비게이션 제어 
            function previewImgHandleMouseUp(event) {  
                // 내용들을 넣는다
                if(obj_this.drag_flag || obj_this.selectCnt2 > 1) return false; 
                
                // 슬라이더 드래그 종료 이벤트
                if (isDragging1) {
                    let eq_idx = obj_this.eq_idx; 
                    if(eq_idx === null) return false;
                    let loaderMain = obj_this.loader_main_obj(eq_idx);  
                    let valueSpan  = loaderMain.querySelector('.slider-value'); // 슬라이더 
                    isDragging1    = false; // 드래그 상태 종료 
                    obj_util.fadeOut(valueSpan,  200);

                    // 드래그, 리사이즈등에 사용되는 커버 판넬
                    let helperDome = document.getElementById(obj_this.helperDomeId);
                    if (helperDome) {
                         helperDome.remove(); // 요소 제거
                    } 
                }

                //미리보기 이미지에서 이미지 드래그
                if (isDragging2) { 
                    let eq_idx = obj_this.eq_idx;
                    if(eq_idx === null) return false;
                    isDragging2 = false;
                    // 드래그, 리사이즈등에 사용되는 커버 판넬 
                    let loaderMain    = obj_this.loader_main_obj(eq_idx);  
                    // 드래그, 리사이즈등에 사용되는 커버 판넬
                    let helperDome = document.getElementById(obj_this.helperDomeId);
                    if (helperDome) {
                         helperDome.remove(); // 요소 제거
                    } 
                }

                if (isDragging3) { 
                    isDragging3 = false;
                    // 드래그, 리사이즈등에 사용되는 커버 판넬 
                    let loaderMain    = obj_this.loader_main_obj(eq_idx);  
                    // 드래그, 리사이즈등에 사용되는 커버 판넬
                    let helperDome = document.getElementById(obj_this.helperDomeId);
                    if (helperDome) {
                         helperDome.remove(); // 요소 제거 
                    }
                }
                if (isDragging4) { 
                    isDragging4 = false;
                    // 드래그, 리사이즈등에 사용되는 커버 판넬 
                    let loaderMain    = obj_this.loader_main_obj(eq_idx);  
                    // 드래그, 리사이즈등에 사용되는 커버 판넬
                    let helperDome = document.getElementById(obj_this.helperDomeId);
                    if (helperDome) {
                         helperDome.remove(); // 요소 제거 
                    }
                }
 
            }// end previewImgHandleMouseUp


            /*===================================
             * 미리보기 네비 이미지 마우스 이동 이벤트
            **---------------------------------*/   
            function previewImgHandleMouseMove2(event) {
                if(obj_this.drag_flag || obj_this.selectCnt2 > 1) return false;

                if (event.target.className !== 'naviImg') {
                    return false;
                }
                if (event.target.className === 'naviImg') {
                    let eq_idx = obj_this.eq_idx;
                    if (eq_idx === null) return false;

                    let loaderMain  = obj_this.loader_main_obj(eq_idx); 
                    let naviImg     = loaderMain.querySelector('.naviImg'); 
                    let naviPointer = loaderMain.querySelector('.naviPointer');
                    let preview     = loaderMain.querySelector('.view_preview');  
                    let previewDIv  = loaderMain.querySelector('.preview_in_div');   
                    let previewImg  = loaderMain.querySelector('.preview_upload_thumb2'); 
                    let imgViewNavi = loaderMain.querySelector('.imgViewNavi'); 
                    const rect = naviImg.getBoundingClientRect();
                    let x = event.clientX - rect.left - ( ( naviPointer.offsetWidth  - 2 )/ 2); // 십자 좌표 타겟의 가운데 위치
                    let y = event.clientY - rect.top  - ( ( naviPointer.offsetHeight - 2 )/ 2); // 십자 좌표 타겟의 가운데 위치  

                    if (x < 0) x = 0;//-1;
                    if (y < 0) y = 0;//-1;
                    if (x > naviImg.offsetWidth  - naviPointer.offsetWidth){
                        x = naviImg.offsetWidth  - naviPointer.offsetWidth;
                    }

                    if (y > naviImg.offsetHeight - naviPointer.offsetHeight){
                        y = naviImg.offsetHeight - naviPointer.offsetHeight;
                    }

                    naviPointer.style.left = x - 0 + 'px';
                    naviPointer.style.top  = y - 0 + 'px';
 
                    // 비율 조정
                    let imgRateX = previewImg.offsetWidth  / imgViewNavi.offsetWidth;
                    let imgRateY = previewImg.offsetHeight / imgViewNavi.offsetHeight;
                    let scaleX   = (previewImg.offsetWidth * 1)  / (naviImg.offsetWidth);
                    let scaleY   = (previewImg.offsetHeight * 1) / (naviImg.offsetHeight);
                    let newLeft  = - x * scaleX;
                    let newTop   = - y * scaleY;

                    // 이동 범위를 제한 (미리보기 영역 밖으로 벗어나지 않도록)
                    let minLeft = -(previewImg.offsetWidth -( previewDIv.offsetWidth - 0));
                    let minTop  = -(previewImg.offsetHeight - previewDIv.offsetHeight);

                    if (newLeft < minLeft) newLeft = minLeft - 10; // 우
                    if (newTop < minTop)   newTop  = minTop  - 10; // 하
                    if (newLeft > - 10) newLeft = 10; // 좌
                    if (newTop  > - 10) newTop  = 10; // 상

                    // ※ 미리보기 이미지 이동
                    if((previewImg.offsetWidth > previewDIv.offsetWidth) )
                    previewImg.style.left = newLeft + 'px';
                    if((previewImg.offsetHeight > previewDIv.offsetHeight))
                    previewImg.style.top  = newTop + 'px'; 
                }
                
            }// end previewImgHandleMouseMove
  
            function previewImgHandleMouseMove(event) {
                let eq_idx = obj_this.eq_idx;
                if (eq_idx === null) return false;

                let loaderMain  = obj_this.loader_main_obj(eq_idx);
                let naviImg     = loaderMain.querySelector('.naviImg');
                let naviPointer = loaderMain.querySelector('.naviPointer');
                let previewDIv  = loaderMain.querySelector('.preview_in_div');
                let previewImg  = loaderMain.querySelector('.preview_upload_thumb2');
                let imgViewNavi = loaderMain.querySelector('.imgViewNavi');

                if (event.target.className !== 'naviImg') return;

                const rect  = naviImg.getBoundingClientRect();
                let offsetX = event.clientX - rect.left;
                let offsetY = event.clientY - rect.top;

                // 네비 포인터 크기
                let pointerWidth  = naviPointer.clientWidth;
                let pointerHeight = naviPointer.clientHeight;

                // 네비 포인터가 마우스 중앙에 위치하도록 조정
                let pointerCenterX = (offsetX - pointerWidth / 2);
                let pointerCenterY = (offsetY - pointerHeight / 2);

                // 네비게이션 내부에서만 포인터 이동 제한
                pointerCenterX = Math.max(0, Math.min(pointerCenterX, naviImg.clientWidth  - pointerWidth - 2));
                pointerCenterY = Math.max(0, Math.min(pointerCenterY, naviImg.clientHeight - pointerHeight - 2));

                // 네비 포인터 위치 설정
                naviPointer.style.left = `${pointerCenterX}px`;
                naviPointer.style.top  = `${pointerCenterY}px`;

                // 확대 비율 계산
                let scaleX = previewImg.clientWidth / imgViewNavi.clientWidth;
                let scaleY = previewImg.clientHeight / imgViewNavi.clientHeight;

                // 마우스 중앙 기준으로 이미지 이동
                let moveX = (pointerCenterX + pointerWidth / 2) * scaleX - previewDIv.clientWidth / 2;
                let moveY = (pointerCenterY + pointerHeight / 2) * scaleY - previewDIv.clientHeight / 2;

                // 보정:: 네비 포인터가 네비게이션의 끝에 도달하면 메인 이미지도 끝으로 이동( 네비 포인터의 정 중앙에 포인터가 위치하므로 이미지의 맨 끝까지 사용못한다 이에 대한 보정 )
                let margin = 6; // 이미지의 css그림자 3픽셀정도의 여유값
                if (pointerCenterX >= naviImg.clientWidth  - pointerWidth ) moveX = previewImg.clientWidth  - previewDIv.clientWidth  + margin; // 우측 끝
                if (pointerCenterY >= naviImg.clientHeight - pointerHeight) moveY = previewImg.clientHeight - previewDIv.clientHeight + margin; // 하단 끝

                // 보정:: 네비 포인터가 네비게이션의 끝에 도달하면 메인 이미지도 끝으로 이동
                if( pointerCenterX <= 0 ) moveX = ( -1 )* margin;
                if( pointerCenterY <= 0 ) moveY = ( -1 )* margin;

                // 메인 이미지 이동
                // ※ 미리보기 이미지 이동
                if((previewImg.offsetWidth > previewDIv.offsetWidth) )
                previewImg.style.left = ( -1 )* moveX +'px'; 
                if((previewImg.offsetHeight > previewDIv.offsetHeight))
                previewImg.style.top  = ( -1 )* moveY +'px';

            }

            /*===================================
             * 미리보기 네비 이미지 마우스 이동 이벤트
            **---------------------------------*/    
            function previewImgGuideLineMouseMove(event) {
                let loaderMain      = obj_this.loader_main_obj(eq_idx); 
                let preview         = loaderMain.querySelector('.view_preview');  
                let verticalRuler   = loaderMain ? loaderMain.querySelector('.verticalRuler') : null; 
                let horizontalRuler = loaderMain ? loaderMain.querySelector('.horizontalRuler') : null;  
                let verticalGuide   = loaderMain ? loaderMain.querySelector('.view_preview .verticalGuide') : null; 
                let horizontalGuide = loaderMain ? loaderMain.querySelector('.view_preview .horizontalGuide') : null; 
                let positonDom      = loaderMain ? loaderMain.querySelector('.position-display') : null;
                let positonPos      = loaderMain ? loaderMain.querySelector('.position-display .pos') : null;
                let positonPixel    = loaderMain ? loaderMain.querySelector('.position-display .pixel') : null;
                let x = event.clientX - g_startX;
                let y = event.clientY - g_startY; 

                if(positonDom === null ) return false;

                if(isDragging3 === true){// verticalGuide 아래로 내려 뻗은 수직의 라인( | ) x만 움직인다 
                    const v_rect = verticalGuide.getBoundingClientRect(); 
                    if( x < 10 ){
                        x = 10;
                    }
                    if( x > preview.offsetWidth - 10){
                        x = preview.offsetWidth - 10;
                    }
                    verticalGuide.style.left = x  + 'px';
                    verticalGuide.style.top  = 0  + 'px';

                    if(x - lineLeft < 0 ){ 
                        positonDom.style.left  = x + 20 + 'px';
                    } else {
                        positonDom.style.left  = x - 90 + 'px';
                    }

                    positonDom.style.top   = y - v_rect.top - 10 + 'px';
                    positonPos.innerHTML   = 'X';
                    positonPixel.innerHTML = x - lineLeft + 'px';
                    positonPixel.innerHTML = parseInt(x - (preview.offsetWidth / 2) + 0) + 'px'; //가로 정 중앙 
                }
                
                if(isDragging4 === true){ // horizontalGuide 옆으로 누운 수평의 라인( - ) y만 움직인다 
                    const h_rect = horizontalGuide.getBoundingClientRect(); 
                    if( y < 10 ){
                        y = 10;
                    }
                    if( y > preview.offsetHeight - 10){
                        y = preview.offsetHeight - 10;
                    }
                    horizontalGuide.style.left = 0  + 'px';
                    horizontalGuide.style.top  = y  + 'px';
                    positonDom.style.left   = x - h_rect.left - 40 + 'px';
                    
                    if(y - lineTop < 0 ){ 
                        positonDom.style.top  = y + 20 + 'px';
                    } else {
                        positonDom.style.top  = y - 40 + 'px';
                    } 
                    positonPos.innerHTML   = 'Y';
                    positonPixel.innerHTML = parseInt(y - (preview.offsetHeight / 2) - 0) + 'px'; // 가로 정 중앙
                }

                // 픽셀 안내 div가 밖으로 넘어가지 않도록
                if( parseInt(positonDom.style.top) <20){
                    positonDom.style.top  =  20 + 'px';
                }
                if( parseInt(positonDom.style.top) > preview.offsetHeight - 60){
                    positonDom.style.top  =  preview.offsetHeight - 60 + 'px';
                }

                if( parseInt(positonDom.style.left) <20){
                    positonDom.style.left  =  20 + 'px';
                }
                if( parseInt(positonDom.style.left) > preview.offsetWidth - 100){// 픽셀 표기div 넓이 + 여유
                    positonDom.style.left  = preview.offsetWidth - 100 + 'px';
                }
                
            }// end previewImgGuideLineMouseMove 
 
            // 아래의 것을 펑션으로 만들고 이벤트 추가하는 형식으로 바꿀것
            /*===================================
             * 이미지 미리보기 콘트롤 > 버튼 클릭 >
             * 100%, 화면에 맞춤, 이미지 확대, 축소하기
            **---------------------------------*/ 
            document.querySelectorAll('.view_typeBt, .view_typeBt.on, .imgCtrPannel .imgCtrL_on, .imgCtrPannel .imgCtrR_on').forEach(button => { 
  
                button.addEventListener('mousedown', () => {

                        let eq_idx      = obj_this.eq_idx;
                        if(eq_idx === null) return false; 
                        let loaderMain  = obj_this.loader_main_obj(eq_idx);  
                        let preview    = loaderMain.querySelector('.view_preview');
                        let previewDIv = loaderMain.querySelector('.preview_in_div');
                        let viewWd     = preview.offsetWidth;
                        let viewHt     = preview.offsetHeight;
                        let imgRatio   = obj_this.getImageRatio(eq_idx, 'wdRatio'); // 이미지 넓이 크기 비율 
                        let imgPercent = Math.round(imgRatio * 1);                  // 퍼센트 이미지 비율
                        let hasClass   = button.classList.toggle('on');
                        let originalWd  = obj_this.nowImgNaturalWidth[eq_idx];      // 원본 이미지 크기
                        let originalHt  = obj_this.nowImgNaturalHeight[eq_idx];  
                        let imgViewNavi = loaderMain.querySelector('.imgViewNavi');

                        isMouseDown    = true; // 마우스가 눌림 상태로 설정

                        // 추가 작업 실행
                        if (button.matches('.view_typeBt, .view_typeBt.on')) { 
                            if (hasClass) {//화면 크기에 따라 높이 또는 넓이에 맞게 맞춰짐
                                button.title ='실제 크기로 확대';// 클릭시 실행할 작업
                                const originalWd  = obj_this.nowImgNaturalWidth[eq_idx];   // 원본 이미지 크기
                                const originalHt  = obj_this.nowImgNaturalHeight[eq_idx];
                                if (viewWd / viewHt > originalWd / originalHt) {
                                    // 공간의 가로비율이 이미지의 가로비율보다 크다면, 높이를 기준으로 리사이즈
                                    // 이 경우 이미지의 높이를 viewHt에 맞추고, 넓이는 비율에 맞게 조정
                                    imgPercent = (( viewHt - obj_this.PAD) / originalHt) * 100;
                                } else {
                                    // 공간의 세로비율이 이미지의 세로비율보다 크다면, 넓이를 기준으로 리사이즈
                                    // 이 경우 이미지의 넓이를 viewWd에 맞추고, 높이는 비율에 맞게 조정 
                                    imgPercent = ((viewWd - obj_this.PAD) / originalWd) * 100; 
                                }
                            } else {//실제크기로 보여줌
                                // 여기에 제거 시 실행할 작업 작성
                                button.title ='화면 크기에 맞춤'; // 클릭시 실행할 작업
                                imgPercent = 90; 
                            }
                        }

                        // 이미지 축소
                        if (button.classList.contains('imgCtrL_on')) {
                            //800-600까지 감소는 50식 감소
                            //600-200까지 감소는 25씩 감소
                            //200- 0 10씩 감소 0일경우엔 1로 맞추고 더이상 줄지 않도록
                            if (imgPercent >= 600) {
                                imgPercent -= imgPercent % 50 === 0 ? 50 : imgPercent % 50;
                            } else if (imgPercent >= 200) {
                                imgPercent -= imgPercent % 25 === 0 ? 25 : imgPercent % 25;
                            } else if (imgPercent > 10){
                                imgPercent -= imgPercent % 10 === 0 ? 10 : imgPercent % 10;
                            } else if (imgPercent > 0){
                                imgPercent -= 1;
                            }

                            // imgPercent 값이 0 이하로 내려가지 않도록 보정
                            imgPercent = Math.max(imgPercent, 1);  
                        }

                        // 이미지 확대
                        // 0 - 200 범위: 10씩 증가
                        // 200 - 600 범위: 25씩 증가
                        // 600 - 800 범위: 50씩 증가
                        if (button.classList.contains('imgCtrR_on')) {
                            if (imgPercent < 10) {
                                imgPercent += 1 - (imgPercent % 1);
                            } else if (imgPercent <= 200) { 
                                imgPercent += 10 - (imgPercent % 10);
                            } else if (imgPercent <= 600) {
                                imgPercent += 25 - (imgPercent % 25);
                            } else if (imgPercent <= 800) {
                                imgPercent += 50 - (imgPercent % 50);
                            }

                            // imgPercent 값이 800을 초과하지 않도록 보정
                            imgPercent = Math.min(imgPercent, 800); 
                        }
  
                        // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 리사이즈된 리턴된 값을 가지고 아래에서
                        // 한번 더 재 측정이 이뤄진다  
                        let reResize    = obj_this.imgView_imgResize(eq_idx, 'track', imgPercent, '2071 Line'); 
                        let imgRatio2   = reResize.newWidth / originalWd; // 리사이즈 이후 반환된 리사이즈 크기로 비율을 측정
                        let imgPercent2 = Math.round(imgRatio2 * 100);    // 퍼센트 이미지 비율 

                        // 미리보기 트랙볼의 위치 업데이트
                        obj_this.imgViewTrackPosition(event, 'btn', eq_idx, imgPercent2, '2076 Line'); 
                        // 이미지 확대,축소 버튼의 모양 변경
                        obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent2); 

                        if(imgPercent <= 1 || imgPercent >= 800){
                            clearInterval(obj_this.set_time_var3); // 반복 작업 중단
                        }
                        
                        // 버튼을 계속 누르고 있을 경우 
                        timeoutId = setTimeout(() => {
                            intervalId = setInterval(function() { 
                                let addRate = 0;
                                let incrementFactor = 0;
                                // 버튼을 누르고 있을 때 속도 조절
                                if(imgPercent < 10){
                                   addRate = 0.01;
                                   incrementFactor = 0.01;
                                } 
                                else
                                if (imgPercent < 50 || imgPercent > 600 ){
                                   addRate = 0.08;
                                   incrementFactor = 0.08;
                                } else {
                                   addRate = 0.1;
                                   incrementFactor = 0.1;
                                }

                                if (button.classList.contains('imgCtrL_on')) { // 이미지 축소 
                                    imgPercent -= Math.ceil((imgPercent + addRate) * incrementFactor);
                                    imgPercent = Math.max(imgPercent, 1); // imgPercent 값이 1 미만으로 내려가지 않도록 보정
                                }
                                else
                                if (button.classList.contains('imgCtrR_on')) { // 이미지 확대 
                                    imgPercent += Math.ceil((imgPercent + addRate) * incrementFactor);
                                    imgPercent = Math.min(Math.max(imgPercent, 1), 800); // imgPercent 값이 800 초과 되지 않도록 보정
                                } 

                                // 이미지 리사이즈및 위치를 가운데로:: 리사이즈시 시간차이로 이전 사이즈를 가져오므로 리사이즈된 리턴된 값을 가지고 아래에서
                                // 한번 더 재 측정이 이뤄진다  
                                let reResize    = obj_this.imgView_imgResize(eq_idx, 'btn', imgPercent, '2113 Line'); 
                                let imgRatio2   = reResize.newWidth / originalWd; // 리사이즈 이후 반환된 리사이즈 크기로 비율을 측정
                                let imgPercent2 = Math.round(imgRatio2 * 100);    // 퍼센트 이미지 비율   
                                // 미리보기 트랙볼의 위치 업데이트
                                obj_this.imgViewTrackPosition(event, 'btn', eq_idx, imgPercent2, '2117 Line'); 
                                // 이미지 확대,축소 버튼의 모양 변경
                                obj_this.imgView_imgCtrlOnOff(eq_idx, imgPercent2);
 
                            }, 100); // 100ms 간격으로 실행
                        },500); 
                });

                // 마우스 업 시 setInterval 멈춤
                button.addEventListener('mouseup', () => { 
                    isMouseDown = false; // 마우스가 눌림 상태 해제
                    clearTimeout(timeoutId);   // setTimeout 중지 (아직 실행되지 않았다면)
                    clearInterval(intervalId); // setInterval 중지
                });
                
                // 마우스가 버튼 영역에서 벗어나도 멈추도록 설정
                button.addEventListener('mouseleave', () => {
                    isMouseDown = false; // 마우스가 눌림 상태 해제
                    clearTimeout(timeoutId);   // setTimeout 중지 (아직 실행되지 않았다면)
                    clearInterval(intervalId); // setInterval 중지
                });
            });



            // 인자를 추가시 참고
            // document.addEventListener('mousemove', (event) => 함수명(event, arg1, arg2));

            /*===================================
             * 미리보기 마우스 오버시 이벤트
            **---------------------------------*/
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseOverListenerActive) {
                document.addEventListener('mouseover', previewImgHandleMouseOver);
                window.isMouseOverListenerActive = true;
            }

            /*===================================
             * 셀렉트 박스 위에서 마우스 휠 이벤트
            **---------------------------------*/  
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseWheelListenerActive) {
                document.addEventListener('wheel', previewImgHandleMouseWheel, { passive: false });
                window.isMouseWheelListenerActive = true;
            }

            /*===================================
             * 미리보기 슬라이더,이미지 이동 마우스 다운시 이벤트
            **---------------------------------*/  
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseDownListenerActive) {
                document.addEventListener('mousedown', previewImgHandleMouseDown);
                window.isMouseDownListenerActive = true;
            }

            /*===================================
             * 마우스 업 이벤트
            **---------------------------------*/  
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseUpListenerActive) {
                document.addEventListener('mouseup', previewImgHandleMouseUp);
                window.isMouseUpListenerActive = true;
            }
               
            /*===================================
             * 미리보기 네비 이미지 마우스 이동 이벤트
            **---------------------------------*/  
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseMoveListenerActive) {
                document.addEventListener('mousemove', previewImgHandleMouseMove); 
                window.isMouseMoveListenerActive = true;
            }

            /*===================================
             * 미리보기 슬라이더, 이미지 마우스 이동 이벤트
            **---------------------------------*/   
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseMoveListenerActive2) {
                document.addEventListener('mousemove', (event) => isDraggingMouseMove(event)); 
                window.isMouseMoveListenerActive2 = true;
            }

            /*===================================
             * 미리보기 이미지 가이드 라인 마우스 이동 이벤트
            **---------------------------------*/  
            // 이벤트 중복 방지 로직 추가
            if (!window.isMouseMoveListenerActive3) {
                document.addEventListener('mousemove', (event) => previewImgGuideLineMouseMove(event)); 
                window.isMouseMoveListenerActive3 = true;
            }

        }, // end imgControllerAct


        // 원본의 넓이와 높이를 기준으로 변환된 넓이 또는 높이중 하나의 입력값을 가지고 나머지 높이 또는 넓이의 값을 알아낸다
        resizeImage : function(originalWidth, originalHeight, newWidth = null, newHeight = null) {
            if (originalWidth <= 0 || originalHeight <= 0) return null; // 잘못된 입력 방지

            if (newWidth !== null && newHeight !== null) {
                // 비율 유지가 필요한 경우: (newWidth / newHeight) !== (originalWidth / originalHeight) 검사 가능
                return { width: newWidth, height: newHeight };
            }
            
            if (newWidth !== null) {
                newHeight = (newWidth / originalWidth) * originalHeight; // 너비 기준 높이 계산
            }
            else if (newHeight !== null) {
                newWidth = (newHeight / originalHeight) * originalWidth; // 높이 기준 너비 계산
            }
            else {
                return null; // 변환할 값이 없으면 null 반환
            }

            return { width: newWidth, height: newHeight };
        },


        imgView_imgResize : function(eq_idx, objType, newVal, line){ 
 
            const obj_this    = MARI.file_uploder.code; 
			const obj_util    = MARI.file_uploder.util; 
            let objLang       = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
            const loaderMain  = obj_this.loader_main_obj(eq_idx);
            let preview       = loaderMain.querySelector('.view_preview');          // 미리보기 공간 
            let previewDiv    = loaderMain.querySelectorAll('.preview_in_div');     // 미리보기 개체 
            let firstDiv      = previewDiv[0];
            let secondDiv     = previewDiv[1] || null;
            let previewImg = objType === 'first' 
                ? firstDiv.querySelector('.preview_upload_thumb2') 
                : (secondDiv?.querySelector('.preview_upload_thumb2') || loaderMain.querySelector('.preview_upload_thumb2'));
           // let originalWd    = Number(obj_this.nowImgNaturalWidth[eq_idx]) ;
           // let originalHt    = Number(obj_this.nowImgNaturalHeight[eq_idx]);
  
            let evt_idx       = obj_this.click_idx[eq_idx]; // 클릭, 드래그시 선택된 idx 
            let aryIdx        = obj_this.getListDataAryIdx(eq_idx, evt_idx) - 1; //데이터 코드에는 1부터 증가이므로 빼준다
            let objType2      = obj_this.getMakeType(eq_idx, evt_idx); 
            let getDatas      = obj_this.getFileInfo2(eq_idx, objType2, aryIdx, 'All', '72'); // 데이터  
            let originalWd    = Number(getDatas.dataImgWidth)  || 184; // 원본 이미지 크기  
            let originalHt    = Number(getDatas.dataImgHeight) || 160; // 원본 이미지 크기 
            // 이미지를 비율값에 맞게 크기를 가감 시킨다
            let scaleFactor   = 0.5; // 확대/축소 비율 0.1
            let maxScale      = 1;   // 최대 확대 비율 1
            let minScale      = 0.1; // 최소 축소 비율 0.1 
            let beforeViewWd  = obj_this.resize_viewWidth[eq_idx];   // 이전 이미지가 들어가는 공간의 크기
            let beforeViewHt  = obj_this.resize_viewHeight[eq_idx];  // 이전 이미지가 들어가는 공간의 크기
            let beforeImgWd   = obj_this.resize_imgWidth[eq_idx];    // 이전 이미지의 크기
            let beforeImgHt   = obj_this.resize_imgHeight[eq_idx];   // 이전 이미지의 크기
            let afterViewWd   = preview.offsetWidth  - obj_this.PAD; // 미리보기에서의 이미지가 들어가는 공간의 현재 크기
            let afterViewHt   = preview.offsetHeight - obj_this.PAD; // 미리보기에서의 이미지가 들어가는 공간의 현재 크기
            let imgWdGab      = beforeViewWd - beforeImgWd;          // 처음 클릭시 이미지 들어가는 공간과 이미지와의 넓이 차이
            let imgHtGab      = beforeViewHt - beforeImgHt;          // 처음 클릭시 이미지 들어가는 공간과 이미지와의 높이 차이

            // 이미지 들어가는 공간에서 이미지의 넓고 좁고에 따른 차이만 더하거나 뺀다 ::: 이미지 공간이 기준이 되고 거기에 + - 가 되는 형식
            let afterViewWd1  = afterViewWd - imgWdGab;              // 이미지 공간 크기 + 이미지가 오버된 크기를 더하거나 모자란 크기를 뺀다
            let afterViewHt1  = afterViewHt - imgHtGab;              // 이미지 공간 크기 + 이미지가 오버된 크기를 더하거나 모자란 크기를 뺀다
            //클릭시 사이즈에서 부터 리사이즈까지 몇 % 증가 되었는지 증가된것을 다시 이전 이미지 넓이 사이즈에 곱해서 리사이징된 넓이를 넣어서 넓이와 높이를 알아냄
            let wd_resized    = obj_this.resizeImage(originalWd, originalHt, afterViewWd1); // 넓이를 기준으로 변경된 사이즈를 리턴 받는다
            let ht_resized    = obj_this.resizeImage(originalWd, originalHt, null, afterViewHt1); // 넓이를 기준으로 변경된 사이즈를 리턴 받는다 
            let newWidth  = 0;
            let newHeight = 0;
            if( objType === 'btn'|| objType === 'track' ){
                newWidth      = (originalWd  * (newVal/100));
                newHeight     = (originalHt * (newVal/100));    
            } else { 
                if( obj_this.drag_bar_flag === true ){
                    newWidth  = wd_resized.width;
                    newHeight = wd_resized.height;
                } else {
                    newWidth  = ht_resized.width;
                    newHeight = ht_resized.height;
                }
            }

            let verticalRuler  = loaderMain ? loaderMain.querySelector('.view_preview .verticalRuler') : null;
            let verticalGuide  = loaderMain ? loaderMain.querySelector('.view_preview .verticalGuide') : null; 
            let imgRatio       = obj_this.getImageRatio(eq_idx, 'ratio'); // 이미지 크기 비율 
            let imgPercent     = Math.round(imgRatio);                    // 퍼센트 이미지 비율  
            let selectInput    = loaderMain.querySelector('.selectInput'); 
            if(!selectInput){
                return false;
            }

            let selectInputVal = selectInput.value;
            let onlyNumbersVal = selectInputVal.replace(/\D/g, ""); // 숫자가 아닌 문자를 모두 제거  
            let viewWd         = preview.offsetWidth;
            let viewHt         = preview.offsetHeight;  
            let posL           = null;
            let posT           = null; 
            let nowImgRect     = previewImg.getBoundingClientRect(); 
            let nowImgWidth    = nowImgRect.width;  // 현재 이미지 너비
            let nowImgHeight   = nowImgRect.height; // 현재 이미지 높이
            let nowImgLeft     = nowImgRect.left;   // 현재 이미지 좌측 지점
            let nowImgTop      = nowImgRect.top;    // 현재 이미지 상단 지점 
            let resizeWeelFlag = false;
 
            if (imgPercent >= 800) imgPercent = 800;
            if (imgPercent <= 1)   imgPercent = 1;
 
            // 각 타입에 따른 분류
            switch (objType) {
                case 'first' : // 리스트에서 선택으로 이미지 체인지시 사용  
                case 'second': // 리스트에서 선택으로 이미지 체인지시 사용 
                    // first,second 내용이 같아 캐이스문을 묶어서 사용한다
                    if(originalWd <= viewWd && originalHt <= viewHt){   
                        newWidth  = originalWd;
                        newHeight = originalHt; 
                        obj_this.imgAddScale = 100;  
                    } 
                    else{ // 공간보다 이미지가 큰
                        let newSize = null; 
                        const originalWd  = obj_this.nowImgNaturalWidth[eq_idx];   // 원본 이미지 크기
                        const originalHt  = obj_this.nowImgNaturalHeight[eq_idx]; 
                        if (viewWd / viewHt > originalWd / originalHt) { // 위에 같은 부분의 이프문에서 차용
                            // 공간의 가로비율이 이미지의 가로비율보다 크다면, 높이를 기준으로 리사이즈
                            // 이 경우 이미지의 높이를 viewHt에 맞추고, 넓이는 비율에 맞게 조정
                            imgPercent = (viewHt/originalHt) * 100;
                            newSize = obj_this.resizeImage(originalWd, originalHt, null, viewHt - obj_this.PAD); // 높이 기준 
                        } else {
                            // 공간의 세로비율이 이미지의 세로비율보다 크다면, 넓이를 기준으로 리사이즈
                            // 이 경우 이미지의 넓이를 viewWd에 맞추고, 높이는 비율에 맞게 조정  
                            imgPercent = (viewWd/originalWd) * 100; 
                            newSize = obj_this.resizeImage(originalWd, originalHt, viewWd - obj_this.PAD, null); // 넓이 기준
                        } 

                        // 선택 후 현재의 미리보기 공간 사이즈에 리사이즈 될수 있도록 넓이 높이, 이미지 비율등을 조정한다
                        newWidth  = newSize.width;
                        newHeight = newSize.height;  
                        obj_this.imgAddScale = ( newWidth / newHeight ) * 100;
                    } 

                    // 초기화
                    obj_this.downWheelCurrentIndex[eq_idx] = 0;// 휠 내림 인덱스용을 0으로   
                    obj_this.upWheelCurrentIndex[eq_idx]   = 0;// 휠 오름 인덱스용을 0으로 
                    break;

                case 'viewResize':  
                    const viewWd1      = viewWd - obj_this.PAD;
                    const viewHt1      = viewHt - obj_this.PAD;
                    const isWideImg    = originalHt <= originalWd;
                    const isLongImg    = originalHt > originalWd;
                    const imgScale     = obj_this.imgAddScale > 0 ? obj_this.imgAddScale / 100 : 1;   
                    const isimgInside  = nowImgWidth + obj_this.PAD < viewWd1 && nowImgHeight + obj_this.PAD < viewHt1; 
                    const isImgFit     = nowImgWidth == viewWd1 || nowImgHeight == viewHt1;  
                    const isImgOutside = nowImgWidth >= viewWd1 || nowImgHeight >= viewHt1;   
                    const beforeWd     = obj_this.resize_viewWidth[eq_idx];             // 미리보기 공간의 이전 크기 
                    const afterViewWd  = parseInt(preview.offsetWidth)  - obj_this.PAD; // 미리보기 공간의 현재 크기
                    const isGab        = (afterViewWd - beforeWd); 

                    if(isimgInside){ // 공간에 비해 크기가 작은
                        // 넓이와 높이를 재 지정  
                        if( obj_this.drag_bar_flag === true ){
                            newWidth  = wd_resized.width;
                            newHeight = wd_resized.height;
                        } else {
                            newWidth  = ht_resized.width;
                            newHeight = ht_resized.height;
                        }
                    }

                    // 갭 이하라면 경계에 맞게
                    if (  (imgWdGab > -10 )) { // 경계선 안에 있고 이미지가 공간 안에 있다면 경계까지만 리사이징
                        if (newWidth >= viewWd1){
                            ({ width: newWidth, height: newHeight } = obj_this.resizeImage(originalWd, originalHt, viewWd1));
                        }  
                        if (newHeight >= viewHt1){
                            ({ width: newWidth, height: newHeight } = obj_this.resizeImage(originalWd, originalHt, null, viewHt1));
                        } 
                    } 
                    else
                    if (  (imgHtGab > -10)) { // 경계선 안에 있고 이미지가 공간 안에 있다면 경계까지만 리사이징
                        if (newWidth >= viewWd1){
                            ({ width: newWidth, height: newHeight } = obj_this.resizeImage(originalWd, originalHt, viewWd1));
                        }  
                        if (newHeight >= viewHt1){
                            ({ width: newWidth, height: newHeight } = obj_this.resizeImage(originalWd, originalHt, null, viewHt1));
                        } 
                    }

                    //=============================
                    //  이미지의 규격이 800%이상 늘지 않도록
                    //=============================
                    if(newWidth > originalWd * 8){ 
                        let resized = obj_this.resizeImage(originalWd, originalHt, (originalWd*8) - obj_this.PAD); // 넓이를 기준으로 변경된 사이즈를 리턴 받는다
                        newWidth  = resized.width;
                        newHeight = resized.height;
                    }
                    if(newHeight > originalWd * 8){ 
                        let resized = obj_this.resizeImage(originalWd, originalHt, null, (originalHt*8) - obj_this.PAD); // 넓이를 기준으로 변경된 사이즈를 리턴 받는다
                        newWidth  = resized.width;
                        newHeight = resized.height;
                    }
                    
                    // 이미지의 규격이 1% 이하로 줄지 않도록
                    if(newWidth < originalWd * 0.01){ 
                        let resized = obj_this.resizeImage(originalWd, originalHt, (originalWd*0.01)); // 넓이를 기준으로 변경된 사이즈를 리턴 받는다
                        newWidth  = resized.width;
                        newHeight = resized.height;
                    }
                    if(newHeight < originalWd * 0.01){ 
                        let resized = obj_this.resizeImage(originalWd, originalHt, null, (originalHt*0.01)); // 넓이를 기준으로 변경된 사이즈를 리턴 받는다
                        newWidth  = resized.width;
                        newHeight = resized.height;
                    }
                     
                    
                    obj_this.downWheelCurrentIndex[eq_idx] = 0;
                    obj_this.upWheelCurrentIndex[eq_idx] = 0;
                    break;

                case 'wheelResize': // 휠 이벤트에 따른 축소, 확대 
                    obj_this.imgResizeMovingFlag = false;
                    event.preventDefault(); // 기본 스크롤 방지

                    // 좀 더 가깝게 만들기 위해서 적당한 수열 공식이 없어서 배열로 만들어 대입
                    let upWheelNum     = obj_this.upWheelNum;
                    let downWheelNum   = obj_this.downWheelNum;
                    let selectInput    = loaderMain.querySelector('.selectInput'); 
                    let selectInputVal = selectInput.value;
                    let onlyNumbersVal = selectInputVal.replace(/\D/g, "");        // 숫자가 아닌 문자를 모두 제거
                    // 히스토리 입력
                    obj_this.historyEvent(eq_idx,  '휠 이벤트에 따른 축소, 확대');
                    
                    // 휠 올리기 함수
                    function onWheelUp() {
                        // upWheelNum 배열에서 onlyNumbersVal보다 큰 첫 번째 값의 인덱스(index) 를 찾는다.
                        // let idx = obj_util.findNextHigherIndex(upWheelNum, onlyNumbersVal)
                        let idx = upWheelNum.findIndex(value => value > onlyNumbersVal);  
                        let aryTotal = obj_this.downWheelNum.length - 1; 
                        obj_this.upWheelCurrentIndex[eq_idx]   = idx;   // 인덱스 갱신 :: targetNum => upWheelNum[idx]
                        obj_this.downWheelCurrentIndex[eq_idx] = aryTotal - idx;
                        return upWheelNum[idx];
                    }

                    // 휠 내리기 함수
                    function onWheelDown() {
                        // upWheelNum 배열에서 onlyNumbersVal보다 큰 첫 번째 값의 인덱스(index) 를 찾는다.
                        let idx      = downWheelNum.findIndex(value => value < onlyNumbersVal); 
                        let aryTotal = obj_this.upWheelNum.length - 1;
                        obj_this.downWheelCurrentIndex[eq_idx] = idx;  // 인덱스 갱신 :: targetNum => downWheelNum[idx]
                        obj_this.upWheelCurrentIndex[eq_idx]   = aryTotal - idx;
                        return downWheelNum[idx];// 인덱스를 통한 값  
                    }
  
                    // 확대, 축소에 따른 넓이 높이 재 계산
                    let imgSize = event.deltaY < 0 ? onWheelUp() : onWheelDown();
                    if( typeof(imgSize) === 'undefined' ){ return false; }
                    
                    // 넓이, 높이, 스캐일 지정
                    newWidth  = originalWd * (imgSize / 100); 
                    newHeight = originalHt * (imgSize / 100);
                    obj_this.imgAddScale  = imgSize;

                    // 축소시만 예외 처리:: 열려진 공간에 맞는 이미지 사이즈 이하로 더 이상 축소되지 않도록
                    if (event.deltaY >= 0) {
                        // 공간안에 이미지가 들어차면 더 이상 줄어들지 않도록
                        // 이미지가 공간 이하 크기라면
                        if(originalWd <= viewWd && originalHt <= viewHt){
                            newWidth    = originalWd;
                            newHeight   = originalHt;
                        }
                        //원본의 이미지가 공간 보다 크다면
                        else {
                            //이미지 넓이가 더큰, 이미지 높이가 더 큰
                            let isWide = originalWd >= originalHt, limit = isWide ? viewWd - obj_this.PAD : viewHt - obj_this.PAD;
                            if ((isWide ? newWidth : newHeight) <= limit) {
                                let newSize = obj_this.resizeImage(originalWd, originalHt, isWide ? limit : null, isWide ? null : limit);
                                newWidth = newSize.width, newHeight = newSize.height;
                                obj_this.imgAddScale = (limit / (isWide ? originalWd : originalHt)) * 100;
                            }
                        }
                    } // 축소시만 예외 처리

                    break; // wheelResize

                case 'track': // 슬라이더 축소, 확대에 따른 이벤트
                    obj_this.imgResizeMovingFlag = false; 
                    // 현재의 비율을 업데이트
                    MARI.file_uploder.code.imgAddScale = imgPercent;
                    // 초기화
                    obj_this.downWheelCurrentIndex[eq_idx] = 0;// 휠 내림 인덱스용을 0으로   
                    obj_this.upWheelCurrentIndex[eq_idx]   = 0;// 휠 오름 인덱스용을 0으로

                    break; // track 

                case 'btn': // 축소 확대 버튼에 따른 축소, 확대 이벤트
                    obj_this.imgResizeMovingFlag = false;  
                    // 현재의 비율을 업데이트
                    MARI.file_uploder.code.imgAddScale = imgPercent;
                    // 초기화
                    obj_this.downWheelCurrentIndex[eq_idx] = 0;// 휠 내림 인덱스용을 0으로   
                    obj_this.upWheelCurrentIndex[eq_idx]   = 0;// 휠 오름 인덱스용을 0으로

                    break; // track

            } // end switch

            // 현재의 공간 넓이 갱신
            if(obj_this.view_dp_wd2 != preview.offsetWidth){
                obj_this.view_dp_wd2 = preview.offsetWidth; 
            }
            
            // 현재의 공간 높이 갱신
            if(obj_this.view_dp_ht2 != preview.offsetHeight){
                obj_this.view_dp_ht2 = preview.offsetHeight; 
            }

            // 중심 좌표 기반으로 위치 조정
            posL = (previewDiv[0].offsetWidth  - newWidth) / 2;
            posT = (previewDiv[0].offsetHeight - newHeight) / 2; 

            /*==================================================
            // ※ 미리보기 이미지를 지원하는 파일이라면 미리보기 이미지 스타일 설정
            **------------------------------------------------*/
            if(previewImg){
                previewImg.style.width  = newWidth  + 'px';
                previewImg.style.height = newHeight + 'px';
                previewImg.style.top    = posT + 'px';
                previewImg.style.left   = posL + 'px'; 
                previewImg.style.transition = (objType === 'viewResize' ) ? 'all 0s' : 'all 0.5s';

                // 현재의 미리보기 이미지 크기를 넣어둔다 ::: all 0.5s 이후에 돔이 스타일 적용 되기에
                setTimeout(() => {
                    // 드래그중이라면 리턴
                    if( !( obj_this.mouse_down_flag ||
                           obj_this.drag_bar_flag || obj_this.resize_bar_flag||
                           obj_this.resizeWd_bar_flag||obj_this.resizeHt_bar_flag ) ){
                           obj_this.resize_imgWidth[eq_idx]  = previewImg.offsetWidth;  // 클릭후 현재의 미리보기 이미지 크기
                           obj_this.resize_imgHeight[eq_idx] = previewImg.offsetHeight; // 클릭후 현재의 미리보기 이미지 크기 
                        return false;
                    }
                }, 550);// 0.5초 이후
            }
            
            if(verticalRuler && verticalRuler !== 'null') verticalRuler.classList.add('hov'); 
            if(verticalGuide && verticalGuide !== 'null') verticalGuide.classList.add('hov');  

            return { objType:objType, newWidth: newWidth, newHeight: newHeight };
 
        },

        imgResizeMovingFlag : false, 
        imgAddScale      : 1,
        upCurrentIndex   : 0,
        downCurrentIndex : 0,
        upWheelCurrentIndex   : [],
        downWheelCurrentIndex : [],
        nowImgPercent : [],

        imgViewTrackPosition : function(event, objType, eq_idx, imgPercent, line){
            const obj_this    = MARI.file_uploder.code; 
            const objLang     = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
			const obj_util    = MARI.file_uploder.util; 
            const loaderMain  = obj_this.loader_main_obj(eq_idx);
            const slider      = loaderMain.querySelector('.slider'); // 슬라이더
            const handle      = slider !== null ? slider.querySelector('.slider-handle') : null;
            const valueSpan   = loaderMain.querySelector('.slider-value');          // 슬라이더  
            const selectInput = loaderMain ? loaderMain.querySelector('.selectInput') : null;  
            const rect        = slider !== null ? slider.getBoundingClientRect() : null;
            const trackWidth  = slider !== null ? slider.offsetWidth : null; // 슬라이더의 전체 너비 
            const minValue    = obj_this.imgMinZoomValue; // 슬라이더의 최소값
            const maxValue    = obj_this.imgMaxZoomValue; // 슬라이더의 최대값
 
            if(handle === null || rect=== null || trackWidth=== null) return false; 

            let imgRatio = obj_this.getImageRatio(eq_idx, 'ratio'); // 이미지 크기 비율
            imgPercent2   = Math.round(imgRatio * 100);             // 퍼센트 이미지 비율 

            const trackPosition = ((imgPercent - minValue) / (maxValue - minValue)) * trackWidth; // 트랙볼 위치 계산
            let offsetX = null;

            if(objType === 'track'){
                offsetX = event.clientX - rect.left;
            } else { 
                offsetX = trackPosition; // 마우스 X 위치
            }

            // 슬라이더 범위를 벗어나지 않도록 제한
            if (offsetX < 0)          { offsetX = 0;          } 
            if (offsetX > trackWidth) { offsetX = trackWidth; }

            // 핸들 위치 업데이트
            if(handle)
            handle.style.left    = offsetX + 'px'; 

            // 퍼센트 만큼 배경색 바꿔 채우기
            let sliderPercent = slider.querySelector('.slider-percent');  // 미리보기 이미지  
            sliderPercent.style.width = offsetX + 'px';
 
            if(typeof(imgPercent) === 'number' && imgPercent > -1)
            valueSpan.textContent =  imgPercent+ '%'; // 슬라이더 값 업데이트

            if(selectInput && typeof(imgPercent) === 'number' && imgPercent > -1)
            selectInput.value     = imgPercent + '%'; // 셀렉트 값 업데이트

        },

 
        imgViewNaviDp : null, // 이미지 미리보기 네비게이션의 디스플레이 상태
        imgView_imgCtrlOnOff : function(eq_idx, newVal){
            const obj_this   = MARI.file_uploder.code; 
            const objLang    = MARI.file_uploder.langObj[obj_this.country];  // 언어 객체에서 선택된 언어 가져오기
			const obj_util   = MARI.file_uploder.util; 
            const getLocal   = obj_util.getFromLocalStorage('uploaderData');
            const loaderMain = obj_this.loader_main_obj(eq_idx);
            let previewImg   = loaderMain.querySelector('.preview_upload_thumb2'); // 미리보기 이미지 
            let imgCtrL_on   = loaderMain.querySelector('.imgCtrL_on');  // 슬라이더  
            let imgCtrL_off  = loaderMain.querySelector('.imgCtrL_off'); // 슬라이더
            let imgCtrR_on   = loaderMain.querySelector('.imgCtrR_on');  // 슬라이더
            let imgCtrR_off  = loaderMain.querySelector('.imgCtrR_off'); // 슬라이더
            
            // 미리보기 넓이에 따라 이미지 확대.축소 슬라이더 보이기 감추기
            let imgCtrPannel = loaderMain.querySelector('.imgCtrPannel');
            let sliderDom    = loaderMain.querySelector('.slider');
            let previewDIv   = loaderMain.querySelector('.preview_in_div');   
            let objWd        = previewDIv.offsetWidth;
            let objHt        = previewDIv.offsetHeight;

            if(!previewImg) { return false; }

            if (newVal <= obj_this.imgMinZoomValue) {
                if(imgCtrL_on)
                imgCtrL_on.classList.replace('imgCtrL_on', 'imgCtrL_off'); 
            } else if (newVal >= obj_this.imgMaxZoomValue) {
                if(imgCtrR_on)
                imgCtrR_on.classList.replace('imgCtrR_on', 'imgCtrR_off');  
            }
            else if (newVal > obj_this.imgMinZoomValue && newVal < obj_this.imgMaxZoomValue) {
                if(imgCtrL_off)
                imgCtrL_off.classList.replace('imgCtrL_off', 'imgCtrL_on');
                if(imgCtrR_off)
                imgCtrR_off.classList.replace('imgCtrR_off', 'imgCtrR_on');
            }

            if(imgCtrPannel){
                // 넓이에 따라 콘틀롤러 버튼들 보이기
                let imgCtrL_on  = loaderMain.querySelector('.imgCtrL_on');
                let imgCtrL_off = loaderMain.querySelector('.imgCtrL_on');
                let imgCtrR_on  = loaderMain.querySelector('.imgCtrR_on');
                let imgCtrR_off = loaderMain.querySelector('.imgCtrR_off');

                if(objWd <= 450){
                    sliderDom.style.display = 'none';
                } else {
                    sliderDom.style.display = 'inline-block';
                }
                if(objWd <= 350){
                    if(imgCtrL_on)  imgCtrL_on.style.display  = 'none';
                    if(imgCtrL_off) imgCtrL_off.style.display = 'none';
                    if(imgCtrR_on)  imgCtrR_on.style.display  = 'none';
                    if(imgCtrR_off) imgCtrR_off.style.display = 'none';
                } else {
                    if(imgCtrL_on)  imgCtrL_on.style.display  = 'inline-block';
                    if(imgCtrL_off) imgCtrL_off.style.display = 'inline-block';
                    if(imgCtrR_on)  imgCtrR_on.style.display  = 'inline-block';
                    if(imgCtrR_off) imgCtrR_off.style.display = 'inline-block';
                }

                // 미리보기 이미지 네비게이션 비율이 적정 이상이면 보이기 
                let imgNaviTime = setTimeout(() => { // ( 트랜지션 사용으로 인해 로드된 후 값을 가져오기 위해 :: setTimeout) 
                    let imgViewNavi = loaderMain.querySelector('.imgViewNavi'); // 미리보기 이미지   
                    let previewImg  = loaderMain.querySelector('.preview_upload_thumb2'); // 미리보기 이미지 

                    if(!previewImg) { return false; }
                    let imgWd       = previewImg.offsetWidth;
                    let imgHt       = previewImg.offsetHeight;   
                    let gap         = 100; // 상하 여유분   
                    let isLarger    = imgWd > (objWd + gap) || imgHt > (objHt + gap);  
                    if( getLocal && getLocal.imgNaviView == 'yes'  && isLarger ){
                        if (imgViewNavi.style.display === 'none' || imgViewNavi.style.display === '') {
                            obj_util.fadeIn(imgViewNavi, 250, 100);
                            obj_this.imgViewNaviDp = 'block';
                        } 
                    } else {
                        if (imgViewNavi.style.display === 'block') {
                            obj_util.fadeOut(imgViewNavi, 250, 100);
                            obj_this.imgViewNaviDp = 'none';
                        } 
                    }
                    clearTimeout(imgNaviTime); 
                }, 750); //'all 0.5s'
            }
        },
             


        consoleAry : function( fileType ){
            let obj_this  = MARI.file_uploder.code;
            let dTa_Ary   = null;
          
            if(fileType === 'modify'){
                dTa_Ary   = MARI.file_uploder.code.dTa_Ary[0].modify_files;
            } else {
                dTa_Ary   = MARI.file_uploder.code.dTa_Ary[0].new_files.files
            }
            let aryLen    = dTa_Ary.length; 
            let resultAry = [];
            let resultAry2 = '\n\n';
            for(let i=0; i<aryLen; i++){
                resultAry.push(dTa_Ary[i].dataFileOriginalName);
                resultAry2 +=dTa_Ary[i].dataFileOriginalName+'\n';
            }
            return resultAry2;
        },
	};// end property  
}// end if(typeof(window.MARI.file_uploder.helper) === "undefined") {

