/* * dpicker 클래스에 datepicker 적용. input type=date 적용으로 대체함 * */ jQuery(document).on("focus",".dpicker",function(){ // jQuery(this).datepicker({ // language: "ko", // autoclose: true, // }); }); /* * 공백제거함수 * */ const trim = function(str){ if( str || str === 0 ){ return str.toString().replace(/^\s+|\s+$/g,""); } return ""; }; /* * 경고창, 모달, notify 정의 * */ let NotyObj = new AWN(); const kuls_alert = function(msg, sfunc, options){ return NotyObj.confirm(msg||'실행 메세지가 없습니다.
오류를 확인하세요.',sfunc||false,false,{labels:{confirm: ''}, ...options}); }; const kuls_confirm = function(title, msg, sfunc, ffunc, options){ //let confirm = NotyObj.confirm(msg||' ',sfunc||(()=>{}),ffunc||(()=>{}),{labels:{confirm: title||msg, confirmOk: '확 인', confirmCancel: '취 소'}, ...options}); let confirm = NotyObj.confirm(msg||' ',sfunc||(()=>{}),ffunc||(()=>{}),{labels:{confirm: title||msg}, ...options}); confirm.remove = confirm.delete; //자동 Close 중지용 백업 if( !sfunc ) confirm.okBtn.addEventListener("click", function(){confirm.remove()}); //Ok 실행함수가 없을경우에만 Ok버튼에 닫기 처리 confirm.cancelBtn.addEventListener("click", function(){confirm.remove()}); //Cancel 버튼에 닫기 처리 if( options && options.dontclose ) confirm.delete = ()=>{}; // 기본 닫기함수 무효화 tab_key_able(); return confirm; }; const kuls_modal = function(msg, options){ let modal = NotyObj.modal(msg, 'kuls_modal', {...options}); let btn = document.createElement("a"); btn.classList.add('bi'); btn.classList.add('bi-x-circle-fill'); btn.style = "position:absolute; right:6px; top:6px; line-height: 0; cursor:pointer;"; modal.remove = modal.delete; //자동 Close 중지용 백업 btn.addEventListener("click",function(){modal.remove();} ); modal.el.querySelector(".awn-popup-body").append(btn); jQuery(modal.el.querySelector(".awn-popup-body:not(:has(.sortable))")).draggable(); if( options && options.resizable ) jQuery(modal.el.querySelector(".awn-popup-body")).resizable({ handles: "n, e, s, w, se, nw", grid: [5,5], }); if( options && options.buttons ){ options.buttons.forEach(btns => { document.querySelectorAll(".awn-popup-kuls_modal "+ btns['tgt']).forEach(btn => { btn.addEventListener("click", function(e){ btns.func(modal, e); }); }); }); } if( options && options.init ){ options.init(modal); } if( options && options.dontclose ) modal.delete = ()=>{}; // 기본 닫기함수 무효화 tab_key_able(); return modal; }; const kuls_loading = function(options){ msg =''; msg+='
' + ' Loading...' + '
'; let loading = NotyObj.modal(msg, 'kuls_modal', {...options,isDeleted:false}); loading.remove = loading.delete; //자동 Close 중지용 백업 loading.delete = ()=>{}; return loading; }; const kuls_success = function(msg){ NotyObj.success(msg,{durations: {success:800}}); }; const kuls_warning = function(msg){ NotyObj.warning(msg,{durations: {warning:5000}}); }; const tab_key_able = function(){ //모달창 탭키 인식가능하도록 적용 let focusable = document.querySelectorAll("#awn-popup-wrapper input:not([type=hidden]), #awn-popup-wrapper textarea, #awn-popup-wrapper button"); let shiftkey = false; focusable.forEach((ipt, idx) => { ipt.addEventListener("keydown",function(e){ switch( e.key ){ case "Tab": if( shiftkey ){ focusable[(focusable.length + (idx-1)) % focusable.length ].focus(); }else{ focusable[(idx+1) % focusable.length ].focus(); } break; case "Shift": shiftkey = true; break; } }); ipt.addEventListener("keyup",function(e){ switch( e.key ){ case "Shift": shiftkey = false; break; } }); } ); } /* * 쿼리2json * */ const qry2json = function(qry){ let qryjson = qry.split(/&|&/).reduce( (js, fld) => { fld = fld.split("="); js[fld[0]] = fld[1]; return js; }, {}); return qryjson; }; /* * url decode * */ const urlSplit = function(surl){ let sppos = surl.indexOf("?"), url = "", qry = "", qryjson={}; if( sppos === -1 ){ if( /[&=]/.test(surl) ){ qry = surl; }else{ url = surl; } }else{ url = surl.substr(0,sppos); qry = surl.substr(sppos+1); } qryjson = qry2json(qry); return { url, qry, qryjson }; }; /* * 리스트 정렬 함수 * */ const getSortQry = function(qry, ofld, oasc){ let q2j = qry2json(qry); if( ofld ) q2j['ofld'] = ofld; if( oasc ) q2j['oasc'] = oasc; if( !oasc ){ if( q2j.oasc == "desc" ){ q2j.oasc = "asc"; }else{ q2j.oasc = "desc"; } } return q2j; }; const sort_page_move = function(qry, ofld, oasc){ let nqry = getSortQry(qry, ofld, oasc); location.href ="?" + Object.keys(nqry).map( key => key+"="+nqry[key] ).join("&"); }; const sort_page_load = function(qry, ofld, oasc){ let nqry = getSortQry(qry, ofld, oasc); document.getElementsByName("ofld")[0].value = nqry.ofld; document.getElementsByName("oasc")[0].value = nqry.oasc; common_page_move( Object.keys(nqry).map( key => key+"="+nqry[key] ).join("&") ); }; /** * List Load 함수 */ const list_page_load = (surl, func) => { let url = urlSplit(surl); if( func ) return func(url.url, url.qry, url.qryjson); return false; }; /** * 날짜 변환 함수 (초 -> 분 -> 시간 -> 일) */ const dateRformat = ( number, conf ) => { number = Number(number); let dan = conf?.dan||'s'; let days = 0, hours = 0, minutes = 0, seconds = 0, rem = 0, retstr = ''; switch( dan ){ case "m": //분단위 number *= 60; break; case "h": //시간단위 number *= 60*60; break; } days = Math.floor( number / (3600*24) ); rem = number % (3600*24); hours = Math.floor(rem / 3600); rem = rem % (3600); minutes = Math.floor(rem / 60); seconds = rem % (60); if( days ) retstr += (retstr?' ':'') + days + (conf?.text?.d||'일'); if( hours ) retstr += (retstr?' ':'') + hours + (conf?.text?.h||'시간'); if( minutes ) retstr += (retstr?' ':'') + minutes + (conf?.text?.m||'분'); if( seconds ) retstr += (retstr?' ':'') + seconds + (conf?.text?.s||'초'); return retstr; } /** * form2url */ const form2qry = (form) => { let frm = new FormData(form); return Array.from(frm.entries()).map( tgt => tgt[0]+'='+tgt[1] ).join("&"); }; /** * form2json */ const form2Json = (form) => { let j_son = {}; Array.prototype.slice.call(form.elements).forEach(function (field) { if (!field.name || field.disabled || ['file', 'reset', 'submit', 'button'].indexOf(field.type) > -1) return; if (field.type === 'select-multiple') { Array.prototype.slice.call(field.options).forEach(function (option) { if (!option.selected) return; j_son[field.name] = option.value; }); return; } if (['checkbox', 'radio'].indexOf(field.type) >-1 && !field.checked) return; j_son[field.name] = field.value; }); return j_son; }; //excel용 숫자를 컬럼(A,B,C...AA,AB,AC 등으로 변경하는 함수) const num2XlsColumn = function(num){ let str = '', temp; while (num > 0) { temp = (num - 1) % 26; str = String.fromCharCode(65 + temp) + str; num = (num - temp)/26 | 0; } return str || undefined; }; //exceljs 라이브러리용 json을 엑셀로 저장. const json2xls = function(filename, title, header, datas){ if( typeof ExcelJS == "undefined" ) return false; filename = filename || "noname.xlsx"; title = title || "제목을 입력하지 않았습니다."; header = header || []; datas = datas || []; filename = filename.replace(/[\*\?\:\\\/\[\]]/,''); title = title.replace(/[\*\?\:\\\/\[\]]/,''); const work_Book = new ExcelJS.Workbook(); work_Book.creator = "쿨스 ICT ("+window.location.protocol+"//"+window.location.hostname+")"; work_Book.subject = "쿨스 ICT - " + title; work_Book.title = "쿨스 ICT - " + title; work_Book.description = "Kuls ICT - " + title; work_Book.keywords = window.location.protocol+"//"+window.location.hostname+" - " + title; work_Book.catetory = "쿨스 ICT"; work_Book.company = "쿨스 ICT (www.kuls.co.kr)"; let work_Sheet = work_Book.addWorksheet(title), all_border = { top: {style:'thin', color: {argb:'FFAAAAAA'}}, left: {style:'thin', color: {argb:'FFAAAAAA'}}, bottom: {style:'thin', color: {argb:'FFAAAAAA'}}, right: {style:'thin', color: {argb:'FFAAAAAA'}}, }, title_css = { font: {'size': 16, }, alignment:{ vertical: 'middle', horizontal: 'center' }, }, thd_css = { border: all_border, fill: { type: 'pattern', pattern: 'solid', fgColor: {argb: 'FFF2F2F2'} }, alignment:{ vertical: 'middle', horizontal: 'center' }, }, col_css = { border: all_border, alignment:{ vertical: 'middle', horizontal: 'center' }, }, sttrow = 1, sttCol = 1, sttFld = num2XlsColumn( sttCol ), endFld = num2XlsColumn( header.length + sttCol - 1 ), now_row = sttrow, ws_row = work_Sheet.getRow( now_row ); ws_row.height = 30; ws_row.getCell(1).value = title; ws_row.getCell(1).style = title_css; work_Sheet.mergeCells(`${sttFld}${now_row}:${endFld}${now_row}`); work_Sheet.getRow(2); if( typeof header[0] == "object" ){ ws_row = work_Sheet.addRow(header.map(h=>h.title)); }else{ ws_row = work_Sheet.addRow(header); } ws_row.eachCell((cell, idx) => { cell.style = thd_css; }); if( typeof header[0] == "object" ){ work_Sheet.columns = header.map( v => { return { key:v.key, width:v.width||15 } } ); } datas.forEach(data => { ws_row = work_Sheet.addRow(data); ws_row.eachCell((cell, idx) => { cell.style = col_css; }); }); work_Book.xlsx.writeBuffer().then((data) => { let blob = new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), url = window.URL.createObjectURL(blob), anchor = document.createElement('a'); anchor.href = url; anchor.download = filename; anchor.click(); window.URL.revokeObjectURL(url); }); }; //exceljs 라이브러리용 엑셀을 Json으로 반환 const xls2json = async function(tgt, options){ let xlsfile = tgt.files[0]; if( !xlsfile ){ kuls_alert("엑셀 파일을 등록해 주세요."); return; } if( !options ) options = {}; let jsonData = [], //엑셀내용이 저장되는 변수 workbook = new ExcelJS.Workbook(); await workbook.xlsx.load( xlsfile ); /*파일 읽어오는 위치 지정*/ let rowIdx = options.rowIdx === undefined ? 2 : Number(options.rowIdx), cellIdx = options.cellIdx === undefined ? 0 : Number(options.cellIdx), ws_keys = workbook._worksheets.keys(), worksheet = workbook.getWorksheet(ws_keys[0]), dataSheet = worksheet._rows.filter( (row,idx) => idx >= rowIdx ); if( !dataSheet.length ){ kuls_alert("데이터가 존재하지 않습니다."); return; } //병합(Merge)정보가 필요할댄 worksheet._merges 를 이용하면 된다. 필요할때 추가요망. dataSheet.forEach( (row, ridx) => { let readRow = ridx + rowIdx, rowJson = [], cellval; row._cells.forEach( (cell, cidx) => { if( cidx < cellIdx ) return; switch( cell.type ){ case 0 : //내용없음(에러셀) case 1 : //병합셀내용 => cell.isMerged 로 확인해야 하지만...gogo cellval = ""; break; case 4 : //날짜 cellval = cell.value.getFullYear() +'-'+ String((cell.value.getMonth()+1)).padStart(2,0) +'-'+ String(cell.value.getDate()).padStart(2,0); break; case 5 : //object cellval = cell.value.text; break; case 2 : //숫자 case 3 : //문자 default : cellval = cell.text; } rowJson.push(cellval); } ); jsonData.push(rowJson); }) if( options.func ){ //options.func 는 콜백방식으로 사용하려고 추가해둔것, async..await로 쓰는게 나을것 같아서 미사용 options.func(jsonData); } return jsonData; }; const formSetVal = function( tgt, tag ){ //form 기본(초기)값 처리용 /** Attribute 가 코딩으로 직접적으로 명시된 태그에만 동작함으로 주의필요. "[data-defval]" * Attribute를 코딩으로 입력하지 않은곳에서 사용하려면 attr("data-defval","") 로 data-defval Attribute를 추가한후 사용한다. */ tgt = tgt || document; if( !tag || tag == "select" ) { /* * select 박스 기본값 selected 처리용 * */ jQuery(tgt).find("select").each(function(){ if( jQuery(this).data("defval") !== undefined ){ jQuery(this).attr("data-defval", jQuery(this).data("defval")); } }); jQuery(tgt).find("select[data-defval]").each(function(){ //Select Box 현재값 지정 let _this = this, selval = jQuery(this).data("defval"); if( typeof selval != "object" ){ selval = [selval]; } selval.forEach( v => { _this.querySelectorAll("option").forEach( opt => { if( opt.value == v ){ opt.selected = true; } }); }); }); } if( !tag || tag == "radio" ) { /* * input radio 기본값 checked 처리용. 유일 선택 기준. * */ jQuery(tgt).find("[type=radio]").each(function(){ if( jQuery(this).data("defval") !== undefined ){ jQuery(this).attr("data-defval", jQuery(this).data("defval")); } }); jQuery(tgt).find("[type=radio][data-defval]").each(function(){ //Input:radio 현재값 지정 if( jQuery(this).val() == trim(jQuery(this).data("defval")) ){ jQuery(this).prop("checked",true); } }); } if( !tag || tag == "date" ) { /* * input radio 기본값 checked 처리용. 유일 선택 기준. * */ jQuery(tgt).find("[type=date]").each(function(){ //Input:date 현재값 지정 if( jQuery(this).data("defval") !== undefined ) { if (jQuery(this).val() !== undefined) { function dateFormat(date) { let month = date.getMonth() + 1; let day = date.getDate(); month = month >= 10 ? month : '0' + month; day = day >= 10 ? day : '0' + day; return date.getFullYear() + '-' + month + '-' + day; } jQuery(this).val(dateFormat(new Date(jQuery(this).data("defval")))); } } }); } if( !tag || tag == "checkbox" ) { /* * input checked 기본값 checked 처리용. * */ jQuery(tgt).find("[type=checkbox]").each(function(){ if( jQuery(this).data("defval") !== undefined ){ jQuery(this).attr("data-defval", jQuery(this).data("defval")); } }); jQuery(tgt).find("[type=checkbox][data-defval]").each(function(){ //Input:checkbox 현재값 지정 jQuery(this).prop("checked",false); //if( /(\[|\{)/.test(chkval) ) chkval = JSON.parse(chkval); let chkval = jQuery(this).data("defval"); if( typeof chkval == "object" ){ if( chkval.indexOf(jQuery(this).val()) !== -1 ){ jQuery(this).prop("checked",true); } }else{ if( jQuery(this).val() == trim(chkval) ){ jQuery(this).prop("checked",true); } } }); } if( !tag ){ /* * 기타 input / textarea 기본값 처리용 * */ jQuery(tgt).find("input:not([type=checkbox]):not([type=radio]):not([type=date]), textarea").each(function(){ if( jQuery(this).data("defval") !== undefined ){ jQuery(this).attr("data-defval", jQuery(this).data("defval")); } }); jQuery(tgt).find("input[data-defval]:not([type=checkbox]):not([type=radio]):not([type=date]), textarea[data-defval]").each(function(){ //Select Box 현재값 지정 if( !jQuery(this).data("defval") || jQuery(this).data("defval") == "null" ){ jQuery(this).data("defval", ""); } jQuery(this).val(trim(jQuery(this).data("defval"))); }); } }; document.querySelectorAll(".btnFindAddr").forEach(tgt => tgt.addEventListener("click",function(){ if( daum ){ new daum.Postcode({ theme: { searchBgColor: "#ECECEC", //검색창 배경색 queryTextColor: "#000" //검색창 글자색 }, oncomplete: function(data) { let zipcode = "", address = ""; if( data ){ switch( data.userSelectedType ){ case "R": //도로명 클릭 address = data.roadAddress; break; case "J": //지번 클릭 address = data.jibunAddress; break; } zipcode = data.zonecode; document.querySelector(tgt.attributes['data-zipcode'].value).value = zipcode; document.querySelector(tgt.attributes['data-address'].value).value = address; } } }).open({popupTitle:'쿨스 우편번호 검색', popupKey:'Kuls'}); } })); let vnLoad_dupPrev = false; const vnLoad = function( tgtsql, url, selector, func ){ //jquery.load 대체 if( vnLoad_dupPrev ) return; // { // console.log('POP Prevent'); // return; // } vnLoad_dupPrev = true; fetch( url ) .then( (response) => response.text() ) .then( (bodyHtml) => { let domhtml = document.createElement('div'); domhtml.innerHTML = bodyHtml; let usehtml = ""; if(selector){ usehtml = domhtml.querySelector(selector).innerHTML; }else{ usehtml = domhtml.innerHTML; } vnLoad_dupPrev = false; if( func ){ func(usehtml); }else{ let tgtdom = document.querySelector(tgtsql); tgtdom.innerHTML = usehtml; } } ); }; /* * 모두 체크 처리 * */ jQuery("body").on("click",".allsel",function(){ let tgt = jQuery(this).data("tgt"), notchkbox = jQuery(this).prop("tagName").toUpperCase() != "INPUT" || jQuery(this).attr("type").toUpperCase() != "CHECKBOX"; if( jQuery(this).is(":checked") || notchkbox ){ jQuery("input[type=checkbox][name^="+tgt+"]").prop("checked", true ); }else if( !notchkbox && !jQuery(this).is(":checked") ){ jQuery("input[type=checkbox][name^="+tgt+"]").prop("checked", false ); } }); /** * Form 기본(초기)값 세팅 실행 */ jQuery(document).ready(function(){ formSetVal(document); });