<script type="text/javascript">
$(document).ready(function() {
	//임의 숫자 세팅
	$("input[name='ipt_calc']").each(function(){
		$(this).val((Math.random() * 100).toFixed());
	});
});

function fnCalc(targetNm){
	//최대값 구하기
	let maxValue = Math.max.apply(null, $("#" + targetNm + "Area input[type='number']").map(function (){return $(this).val();}).get());
	//0을 제외한 최소값 구하기
	let minValue = Math.min.apply(null, $("#" + targetNm + "Area input[type='number']").map(function (){return $(this).val() == 0 ? 99999 : $(this).val();}).get());

	$("#sp_area").text(targetNm);
	$("#sp_max").text(maxValue);
	$("#sp_min").text(minValue);
}
</script>

	<div>
		<div>area : <span id="sp_area"></span></div>
		<div>max : <span id="sp_max"></span></div>
		<div>min : <span id="sp_min"></span></div>
	</div>
	<br /><br />
	<div id="firstArea">
		<div>firstArea <button type="button" onclick="fnCalc('first');">calc</button></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
	</div>
	<div id="secondArea">
		<div>secondArea <button type="button" onclick="fnCalc('second');">calc</button></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
		<div><input type="number" name="ipt_calc" value="" /></div>
	</div>
반응형

스크립트로 엑셀 업로드가 가능하여 테스트해보고 스크립트로 Export도 가능할듯하여 테스트.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>엑셀 Export 테스트</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.9/xlsx.full.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js"></script>
<script>
	function upload(event) {
		var input = event.target;
		var reader = new FileReader();
		reader.onload = function() {
			var fdata = reader.result;
			var read_buffer = XLSX.read(fdata, {type : 'binary'});
			
			var xlsArea = document.getElementById("xlsArea");
			var tableStr = "<table id='tableData' style='border:1px solid;'>";
			
			read_buffer.SheetNames.forEach(function(sheetName) {
				var rowdata = XLSX.utils.sheet_to_json(read_buffer.Sheets[sheetName]);
				//console.log("[" + sheetName + "] 시트 데이터 : " + JSON.stringify(rowdata));
				
				$.each(rowdata, function(i, coldata){
					//console.log(rowdata);
					
					//엑셀 Header 세팅
					if(i == 0){
						tableStr += "<tr>";
						$.each(coldata, function(colHeader, colText){
							tableStr += "<th style='color:red;width:500px;border:1px solid;'>" + colHeader + "<th>";
						});
						tableStr += "</tr>";
					}
					
					//엑셀 내용 세팅
					tableStr += "<tr>";
					$.each(coldata, function(colHeader, colText){
						tableStr += "<td style='border:1px solid;'>" + colText + "<td>";
					});
					tableStr += "</tr>";
				});
			});
			
			tableStr += "</table>";
			xlsArea.innerHTML = tableStr;
			//console.log(tableStr);
		};
		reader.readAsBinaryString(input.files[0]);
	}
	
	var excelHandler = {
		getExcelFileName : function() {
			return 'table-test.xlsx';
		},
		getSheetName : function() {
			return 'Table Test Sheet';
		},
		getExcelData : function() {
			return document.getElementById('tableData');
		},
		getWorksheet : function() {
			return XLSX.utils.table_to_sheet(this.getExcelData());
		}
	};
	
	function s2ab(s) { 
		var buf = new ArrayBuffer(s.length); //convert s to arrayBuffer
		var view = new Uint8Array(buf);  //create uint8array as viewer
		for (var i=0; i<s.length; i++) view[i] = s.charCodeAt(i) & 0xFF; //convert to octet
		return buf;
	}
	
	function fnExport(){
		// step 1. workbook 생성
		var wb = XLSX.utils.book_new();
		
		// step 2. 시트 만들기 
		var newWorksheet = excelHandler.getWorksheet();
		
		// step 3. workbook에 새로만든 워크시트에 이름을 주고 붙인다.  
		XLSX.utils.book_append_sheet(wb, newWorksheet, excelHandler.getSheetName());
		
		// step 4. 엑셀 파일 만들기 
		var wbout = XLSX.write(wb, {bookType:'xlsx',  type: 'binary'});
		
		// step 5. 엑셀 파일 내보내기 
		saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), excelHandler.getExcelFileName());
	}
</script>

</head>
<body>
	<div style="float: left;">
		<input type="file" id="id_file_upload" onchange="upload(event)"/>
	</div>
	<div style="float: right;">
		<button type="button" id="btnExport" onclick="fnExport();">엑셀 내보내기</button>
	</div>
	<br /><br />
	<div id="xlsArea"></div>
</body>
반응형
    <script>
        $(function(){
            //datepicker
            $('.datepicker').not('.readonly').datepicker({
                format: 'dd-mm-yyyy',
                startDate: '+1d'
            }).on("blur", function(){
            	var dataRegexp = /[0-9]{4}-?(0[1-9]|1[012])-?(0[1-9]|[12][0-9]|3[01])/;
                if (!dataRegexp.test($(this).val()) ) {
                    $(this).val("");
                }
            });
            $.datepicker.setDefaults({
                dateFormat: 'yymmdd',
                prevText: '이전 달',
                nextText: '다음 달',
                monthNames: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
                monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'],
                dayNames: ['일', '월', '화', '수', '목', '금', '토'],
                dayNamesShort: ['일', '월', '화', '수', '목', '금', '토'],
                dayNamesMin: ['일', '월', '화', '수', '목', '금', '토'],
                showMonthAfterYear: true,
                changeYear: true, //콤보박스에서 년 선택 가능
                changeMonth: true, //콤보박스에서 월 선택 가능
                yearRange: 'c-100:c+10'
            });
        });
    </script>
반응형

스크립트로 엑셀 업로드가 가능하여 테스트해봄.

 

case 1) 엑셀을 업로드하여 화면에 단순 표시

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>엑셀 업로드 테스트</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.9/xlsx.full.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
	function upload(event) {
		var input = event.target;
		var reader = new FileReader();
		reader.onload = function() {
			var fdata = reader.result;
			var read_buffer = XLSX.read(fdata, {type : 'binary'});
			
			var xlsArea = document.getElementById("xlsArea");
			var tableStr = "<table style='border:1px solid;'>";
			
			read_buffer.SheetNames.forEach(function(sheetName) {
				var rowdata = XLSX.utils.sheet_to_json(read_buffer.Sheets[sheetName]);
				//console.log("[" + sheetName + "] 시트 데이터 : " + JSON.stringify(rowdata));
				
				$.each(rowdata, function(i, coldata){
					//console.log(rowdata);
					
					//엑셀 Header 세팅
					if(i == 0){
						tableStr += "<tr>";
						$.each(coldata, function(colHeader, colText){
							tableStr += "<th style='color:red;width:500px;border:1px solid;'>" + colHeader + "<th>";
						});
						tableStr += "</tr>";
					}
					
					//엑셀 내용 세팅
					tableStr += "<tr>";
					$.each(coldata, function(colHeader, colText){
						tableStr += "<td style='border:1px solid;'>" + colText + "<td>";
					});
					tableStr += "</tr>";
				});
			});
			
			tableStr += "</table>";
			xlsArea.innerHTML = tableStr;
			//console.log(tableStr);
		};
		reader.readAsBinaryString(input.files[0]);
	}
</script>

</head>
<body>
	<input type="file" id="id_file_upload" onchange="upload(event)"/>
	<br /><br />
	<div id="xlsArea"></div>
</body>
</html>

 

case 2) 엑셀을 업로드하여 화면에서 수정 후 서버에 반영

(원래 엑셀을 서버로 업로드하는 부분과 export 하는 부분을 구현하려 하였으나 화면에 보여줄때 input 등으로 표시하고 수정하여 서버에 반영하면 필요없을 듯하여 수정)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>엑셀 업로드 테스트</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.9/xlsx.full.min.js"></script>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
	function upload(event) {
		var input = event.target;
		var reader = new FileReader();
		reader.onload = function() {
			var fdata = reader.result;
			var read_buffer = XLSX.read(fdata, {type : 'binary'});
			
			var $xlsArea = $("#xlsArea");
			var $table = $("<table>", {style:"border:1px solid;"});
			
			read_buffer.SheetNames.forEach(function(sheetName) {
				var rowdata = XLSX.utils.sheet_to_json(read_buffer.Sheets[sheetName]);
				//console.log("[" + sheetName + "] 시트 데이터 : " + JSON.stringify(rowdata));
				
				$.each(rowdata, function(i, coldata){
					//console.log(rowdata);
					
					//엑셀 Header 세팅
					if(i == 0){
						var $headerTr = $("<tr>");
						$.each(coldata, function(colHeader, colText){
							var $th = $("<th>", {style : 'color:red;width:500px;border:1px solid;', text : colHeader});
							$headerTr.append($th);
						});
						$table.append($headerTr);
					}
					
					//엑셀 내용 세팅
					$tr = $("<tr>");
					$.each(coldata, function(colHeader, colText){
						var $td = $("<td>", {style : 'border:1px solid;'});
						var $ipt = $("<input>", {type : "input", value : colText, name : colHeader, style : "width:97%;"});
						$td.append($ipt);
						$tr.append($td);
					});
					$table.append($tr);
				});
			});
			
			$xlsArea.append($table);
			//console.log(tableStr);
		};
		reader.readAsBinaryString(input.files[0]);
	}
</script>

</head>
<body>
	<input type="file" id="id_file_upload" onchange="upload(event)"/>
	<br /><br />
	<div id="xlsArea"></div>
</body>
</html>

 

 

반응형

input type이 number 경우 maxlength가 먹히지 않어 스크립트 제어가 필요해짐.

/* ********************************************************
 * 기타 class 이벤트 적용
 * vPoint12 : 정수 10자리 소수점 2자리 까지 입력되도록
 * vNum10 : 정수만 10자리 입력되도록
 ******************************************************** */
function fnEtcClassEvent(){
    $(".vPoint12").each(function(){
        // .(마침표)가 양끝에 있는 케이스를 처리
        $(this).off('blur').on('blur',function(e){
            var value = $(this).val();
            var regExp = /^\.|\.$/;
            if(regExp.test(this.value)){
                $(this).val(value.replace('.',''));
            }
        });
        
        // 소수점 둘째자리까지의 실수만 입력 허용
        $(this).off('input').on('input',function(e){
            var value = $(this).val();
            var regExp = /^\d{0,10}(\.\d{0,2})?$/;
            if(!regExp.test(this.value)){
                $(this).val(value.substring(0,value.length-1));
            }
        });
        
        // 숫자와 .(마침표)만 입력 허용
        $(this).off('keypress').on('keypress',function(e){
            e = e || window.event;
            var charCode = e.which || e.keyCode;
            if (!((charCode >= 48 && charCode <= 57) || charCode === 46)){
                return false;
            }
        });
    });
    
    $(".vNum10").each(function(){
        // 정수만 입력 허용
        $(this).off('input').on('input',function(e){
            var value = $(this).val();
            var regExp = /^\d{0,10}$/;
            if(!regExp.test(this.value)){
                $(this).val(value.substring(0,value.length-1));
            }
        });
        
        // 숫자만 입력 허용
        $(this).off('keypress').on('keypress',function(e){
            e = e || window.event;
            var charCode = e.which || e.keyCode;
            if (!((charCode >= 48 && charCode <= 57))){
                return false;
            }
        });
    });
}

반응형
/* ********************************************************
 * 기타 벨리데이션
 * vReq : 필수입력 체크(class)
 ******************************************************** */
function fnEtcValid(){
	var isPass = true;
	$.each($(".vReq"), function(idx, obj){
		if(obj.value == "" && isPass){
			var vId = obj.id;
			var vLabel = $("label[for='" + vId + "']").text() || $("#" + vId).attr("title");
			var vStr = vLabel == "" ? "" : "[ " + vLabel + " ] 항목은 ";
			isPass = false;
			alert(vStr + "필수입력 항목입니다.");
			obj.focus();
			return false;
		}
	});
	return isPass;
}
반응형
$(document).ready(function() {
    // validate 전화번호 형식 추가
    jQuery.validator.addMethod("phone", function(phone_number, element) {
        phone_number = phone_number.replace(/\s+/g, ""); 
        return this.optional(element) || phone_number.length > 9 && phone_number.match(/^(01[016789]{1}|02|0[3-9]{1}[0-9]{1})-?[0-9]{3,4}-?[0-9]{4}$/);
    }, "잘못된 입력 형식입니다");
    
    // validate date 형식 추가
    jQuery.validator.addMethod("date", function(value, element) {
        return this.optional(element) || value.match(/^(19|20)?\d{2}[/., -](0?[1-9]|1[0-2])[/., -](0?[1-9]|[12][0-9]|3[0-1])$/);
    }, "잘못된 입력 형식입니다");
});
반응형

* Tabulator Tree 세팅은 아래의 이전 글 참조


Tabulator Tree 데이터 세팅 및 노드 추가 처리 스크립트



1.Tabulator 생성시 columns에 아래 체크박스 컬럼 추가


            {

                title:"매핑여부",

                field:"mappingGubun",

                width:80,

                hozAlign:"center",

                download:false,

                vertAlign:"middle",

                editor:"tickCross",

                formatter:"tickCross",

                formatterParams: {

                    allowTruthy:true,

                    tickElement:"<input type='checkbox' checked>",

                    crossElement:"<input type='checkbox'>"

                },

                cellEdited:function(cell) { 

                    if (cell.getValue())

                        checkedTreeNode(menuMngSheet, cell, 1); //해당 체크 박스 및 하위 체크박스 체크

                    else

                        checkedTreeNode(menuMngSheet, cell, 0); //해당 체크 박스 및 하위 체크박스 체크해제

                },

                headerFilter:"tickCross",

                headerFilterEmptyCheck:function(value){

                    fnHeaderCheck(value); //체크박스 전체 체크

                    return true;

                }

            },


2. Tabulator Tree 체크박스 관련 함수 추가(3레벨 메뉴까지 있는 Tree를 기준으로 하였음. 상황에 맞게 수정)


//Tree 체크박스 체크시 하위 노드 체크기능

function checkedTreeNode(vSheet, cell, vCheckValue){

    var rows = vSheet.getRows();

    

    var row = cell.getRow();

    var sSeq = row.getData()["sSeq"];

    

    var isChecked = false;

    var isCheckedLvl = -1;

    var isPass = false;


    if(rows != null && rows.length > 0){

        //1레벨 확인

        for(var i = 0 ; i < rows.length ; i++){

            var lvl1Row = rows[i];

            var lvl1Children = rows[i].getTreeChildren();

            

            if(lvl1Row.getData()["sSeq"] == sSeq && !isPass){

                isChecked = true;

                isCheckedLvl = lvl1Row.getData()["menuLvl"];

                if(lvl1Row.getCell("mappingGubun")){

                    cellEditedCallback(lvl1Row.getCell("mappingGubun"), "U", vCheckValue);

                }

            }

            if(lvl1Children != undefined){

                //2레벨 확인

                for(var j = 0 ; j < lvl1Children.length ; j++){

                    var lvl2Row = lvl1Children[j];

                    var lvl2Children = lvl2Row.getTreeChildren();

                    

                    if((lvl2Row.getData()["sSeq"] == sSeq || (isChecked && isCheckedLvl != lvl2Row.getData()["menuLvl"])) && !isPass){

                        isChecked = true;

                        isCheckedLvl = isCheckedLvl == -1 ? lvl2Row.getData()["menuLvl"] : isCheckedLvl;

                        if(lvl2Row.getCell("mappingGubun")){

                            cellEditedCallback(lvl2Row.getCell("mappingGubun"), "U", vCheckValue);

                        }

                    }

                    if(lvl2Children != undefined){

                        //3레벨 확인

                        for(var k = 0 ; k < lvl2Children.length ; k++){

                            var lvl3Row = lvl2Children[k];

                            

                            if((lvl3Row.getData()["sSeq"] == sSeq || (isChecked && isCheckedLvl != lvl3Row.getData()["menuLvl"])) && !isPass){

                                isChecked = true;

                                isCheckedLvl = isCheckedLvl == -1 ? lvl3Row.getData()["menuLvl"] : isCheckedLvl;

                                if(lvl3Row.getCell("mappingGubun")){

                                    cellEditedCallback(lvl3Row.getCell("mappingGubun"), "U", vCheckValue);

                                }

                            }

                            if(isChecked && isCheckedLvl == lvl3Row.getData()["menuLvl"]) isPass = true;

                        }

                    }

                    if(isChecked && isCheckedLvl == lvl2Row.getData()["menuLvl"]) isPass = true;

                }

            }

            if(isChecked && isCheckedLvl == lvl1Row.getData()["menuLvl"]) isPass = true;

        }

    }

}


//Tree 전체 체크박스 체크시 하위 노드 체크기능

function checkedAllTreeNode(vSheet, vCheckValue){

    var treeData = vSheet.getData();

    

    if(treeData != null && treeData.length > 0){

        for(var i = 0 ; i < treeData.length ; i++){

            var menuLvl1Map = treeData[i];

            menuLvl1Map.mappingGubun = vCheckValue;

            menuLvl1Map.sStatus = "U";

            

            //1레벨 하위항목

            if(menuLvl1Map._children != undefined) {

                for(var j = 0 ; j < menuLvl1Map._children.length ; j++){

                    var menuLvl2Map = menuLvl1Map._children[j];

                    menuLvl2Map.mappingGubun = vCheckValue;

                    menuLvl2Map.sStatus = "U";

                    

                    //2레벨 하위항목

                    if(menuLvl2Map._children != undefined) {

                        for(var k = 0 ; k < menuLvl2Map._children.length ; k++){

                            var menuLvl3Map = menuLvl2Map._children[k];

                            menuLvl3Map.mappingGubun = vCheckValue;

                            menuLvl3Map.sStatus = "U";

                        }

                    }

                }

            }

        }    

    }

    vSheet.setData(treeData);

}



반응형

<style type="text/css">

// 미디어쿼리를 이용한 가로모드, 세로모드일때의 css 적용 방법

@media all and (orientation:portrait) {

// 세로모드일때의 css 적용

}

@media all and (orientation:landscape) {

// 가로모드일때의 css 적용

}

</style>


<script type="text/javascript">

$(document).ready(function() {

// matchMedia를 이용한 가로모드, 세로모드일때의 script 적용 방법

var media = window.matchMedia("(orientation: portrait)");

if (media.matches) {

// 세로모드일때의 script 적용

}

else{

// 가로모드일때의 script 적용

}

});

</script>


cf. 같은 내용으로 window.innerWidth와 window.innerHeight의 크기를 비교하여 가로모드인지 세로모드인지 판별할 수 있다.

반응형

1. Tabulator Grid 객체 생성


cfgItemSheet = new Tabulator("#sheet-containerItem", {

    height:"750px", // virtualDom 사용위해 필수

        layout:"fitColumns",

    headerSort:false,

        selectable: 1,

        dataTree:true,

        dataTreeStartExpanded:true,

        rowClick:function(e, row){

        //selected Row 없어지는 것 방지

        var selectedData = cfgItemSheet.getSelectedData();

        if(selectedData == "") row.toggleSelect();

        },

        ajaxConfig: "POST",

        ajaxContentType:"json",

        ajaxResponse:function(url, params, response) {

    if (response.Message === "OK") {

$('#message').css("color", "#FFFFFF");

$('#message').html("* 조회 완료 : 총 " + response.Data.length + "건");

        return bindListToTree(response.Data);

} else {

$('#message').css("color", "#FF3A00");

$('#message').html("* " + response.Message);

return [];

}

        },

        columns:[

            {

            title:"항목관리",

            columns:[

            {

                    title:"번호",

                    field:"sSeq",

                    width:80,

                    minWidth:60,

                    hozAlign:"left"

            },

            {

                title:"상태",

                field:"sStatus",

                width:80,

                minWidth:60,

                hozAlign:"center",

                download:false,

                formatter: "lookup",

                formatterParams: {

                "D":"삭제", "I":"입력", "U":"수정", undefined:""

                }

            },

            {

            title: "항목명",

                    field: "itemNm",

                    hozAlign:"center",

editor:"input",

            cellEdited:function(cell) {

            var rowData = cell.getRow().getData();

            if (rowData.sStatus != "I")

            cellEditedCallback(cell, "U", 0);

            },

                    validator : ["maxLength:100"]

            },

            {

            title: "항목ID",

                    field: "itemId",

                    download: true,

                    hozAlign:"center",

                    visible : false

            },

            {

            title: "상위항목ID",

                    field: "itemTop",

                    hozAlign:"center",

                    download: true,

                    visible : false

            },

            {

            title: "레벨",

                    field: "itemLvl",

                    hozAlign:"center",

                    download: true,

                    visible : false

            },

            {

            title: "정렬순서",

                    field: "sortOrder",

                    hozAlign:"center",

editor:"input",

            cellEdited:function(cell) {

            var rowData = cell.getRow().getData();

            if (rowData.sStatus != "I")

            cellEditedCallback(cell, "U", 0);

            },

                    validator : ["integer", "maxLength:10"]

            },

        {

        title: "사용여부",

                field: "useYn",

                hozAlign:"center",

                editor:"select",

        formatter: "lookup",

        formatterParams: {"Y":"사용", "N":"미사용"},

        editorParams:{

        values:{"Y":"사용", "N":"미사용"}

        },

                    cellEdited:function(cell) {

                    var rowData = cell.getRow().getData();

                    if (rowData.sStatus != "I")

                    cellEditedCallback(cell, "U", 0);

                    }

        }

            ]

            }

        ]

    });


2. 노드 추가 관련 스크립트


//최상위 항목 등록

function addActionHandlerUp(ev) {

var newSSeq = searchTreeDataLength(cfgItemSheet) + 1;

cfgItemSheet.addRow({ "sStatus":"I", "sDelCheck":0, "sSeq":newSSeq, "itemLvl":"0", "itemId":"", "itemTop":vGrpId, "useYn":"Y"}, true);

//selected Row 체크

var rows = cfgItemSheet.getRows();

rows[0].toggleSelect();

}


//하위 항목 등록

function addActionHandlerDown(ev) {

var sheetData = cfgItemSheet.getData();

var selectedData = cfgItemSheet.getSelectedData()[0];


if(selectedData.sStatus == "I"){

$('#message').html("* 상위레벨을 먼저 저장해야 합니다.");

}

else if(parseInt(selectedData.itemLvl, 10) >= 2){

$('#message').html("* 3레벨까지만 생성이 가능합니다.");

}

else{

//Tree Data Row 추가

sheetData = addSelectedTreeDataRow(cfgItemSheet);


//Tree Data 세팅 및 세팅 후 selected Row 처리

cfgItemSheet.setData(sheetData).then(function(){

if(cfgItemSheet.getDataCount() > 0){

//신규 생성 Tree Data Row Selected

selectedTreeNewRow(cfgItemSheet);

}

});

}

}


3. 저장시 관련 스크립트


function saveActionHandler(ev) {

ev.preventDefault();


// 입력/수정/삭제 할 행

let rows = searchTreeData(cfgItemSheet, "sStatus", ["D", "I", "U"]);


//변경된 Row의 데이터를 JSON 형태로 받음.

//var jsonString = cfgItemSheet.GetSaveJson();

if(rows.length < 1) {

$('#message').html("* 저장할 데이터가 없습니다!");

return;

}

// 신호장치명, 장치코드, 정렬순서 공백 체크

let itemNmRows = searchTreeData(cfgItemSheet, "itemNm", [undefined, ""]);

if (itemNmRows.length > 0) {

alert("항목명을 확인해주십시오!");

return;

}

let sortOrderRows = searchTreeData(cfgItemSheet, "sortOrder", [undefined, ""]);

if (sortOrderRows.length > 0) {

alert("정렬순서를 확인해주십시오!");

return;

}

if(confirm("변경하신 항목관리 정보를 저장하시겠습니까?")) {

let obj = {

schGrpId : vGrpId,

data: rows

};


cfgItemSheet.setData("/cfgItemAction.do", obj, "POST").then(function(){

if(cfgItemSheet.getDataCount() > 0){

var rows = cfgItemSheet.getRows();

rows[0].toggleSelect();

}

});

}

}


4. Tree 관련 스크립트


//list데이터 구조를 Tree데이터 구조로 변환하여 리턴

function bindListToTree(listData){

var treeData = new Array();

var itemLvl1Cnt = 0;

var itemLvl2Cnt = 0;

if(listData != null && listData.length > 0){

for(var i = 0 ; i < listData.length ; i++){

var map = listData[i];

//1레벨 세팅

if(map.itemLvl == 0) {

treeData[itemLvl1Cnt++] = map;

itemLvl2Cnt = 0;

}

//2레벨 세팅

else if(map.itemLvl == 1) {

var lvl1Map = treeData[itemLvl1Cnt - 1];

var lvl1SubList = lvl1Map._children;

if(lvl1SubList == undefined) {

lvl1SubList = new Array();

}

lvl1SubList[lvl1SubList.length] = map;

lvl1Map._children = lvl1SubList;

treeData[itemLvl1Cnt - 1] =  lvl1Map;

itemLvl2Cnt++;

}

//3레벨 세팅

else if(map.itemLvl == 2) {

var lvl1Map = treeData[itemLvl1Cnt - 1];

var lvl1SubList = lvl1Map._children;

var lvl2Map = lvl1SubList[itemLvl2Cnt - 1];

var lvl2SubList = lvl2Map._children;

if(lvl2SubList == undefined) {

lvl2SubList = new Array();

}

lvl2SubList[lvl2SubList.length] = map;

lvl2Map._children = lvl2SubList;

lvl1SubList[itemLvl2Cnt - 1] = lvl2Map;

lvl1Map._children = lvl1SubList;

treeData[itemLvl1Cnt - 1] = lvl1Map;

}

}

}

return treeData;

}


//Tree데이터 구조를 list데이터 구조로 변환하여 리턴

function bindTreeToList(treeData){

var listData = new Array();

var listCnt = 0;

if(treeData != null && treeData.length > 0){

for(var i = 0 ; i < treeData.length ; i++){

var lvl1Map = treeData[i];

listData[listCnt++] = lvl1Map;

//1레벨 하위항목

if(lvl1Map._children != undefined) {

for(var j = 0 ; j < lvl1Map._children.length ; j++){

var lvl2Map = lvl1Map._children[j];

listData[listCnt++] = lvl2Map;

//2레벨 하위항목

if(lvl2Map._children != undefined) {

for(var k = 0 ; k < lvl2Map._children.length ; k++){

var lvl3Map = lvl2Map._children[k];

listData[listCnt++] = lvl3Map;

}

}

}

}

}

}

return listData;

}


//Tree데이터에서 조건에 맞는 데이터를 찾아 list데이터 구조로 변환하여 리턴

function searchTreeData(vSheet, vField, vParamArr){

var treeData = vSheet.getData();

var listData = bindTreeToList(treeData);

var searchData = new Array();

var searchCnt = 0;

if(listData != null && listData.length > 0){

for(var i = 0 ; i < listData.length ; i++){

var map = listData[i];

for(var j = 0 ; j < vParamArr.length ; j++){

if(map[vField] == vParamArr[j]){

searchData[searchCnt++] = map;

}

}

}

}

return searchData;

}


//Tree데이터의 총 length를 리턴

function searchTreeDataLength(vSheet){

var treeData = vSheet.getData();

var listData = bindTreeToList(treeData);

return listData.length;

}


//선택된 Tree Data Row 추가

function addSelectedTreeDataRow(vSheet){

var sheetData = vSheet.getData();

var selectedData = vSheet.getSelectedData()[0];

var itemLvl = parseInt(selectedData.itemLvl, 10) + 1;

var itemTop = selectedData.itemTop;

//Tree Data Row 추가

for(var i = 0 ; i < sheetData.length ; i++){

var lvl1Map = sheetData[i];

var newSSeq = searchTreeDataLength(vSheet) + 1;

//1레벨 항목 확인

if(lvl1Map.itemId == selectedData.itemId){

var newItemTop = "";

var newItemLvl = 0;

if(lvl1Map._children != undefined){

newItemTop = lvl1Map.itemId;

newItemLvl = parseInt(lvl1Map.itemLvl, 10) + 1;

}

else{

lvl1Map._children = new Array();

newItemTop = lvl1Map.itemId;

newItemLvl = parseInt(lvl1Map.itemLvl, 10) + 1;

}

lvl1Map._children[lvl1Map._children.length] = {"sStatus":"I", "sDelCheck":0, "sSeq":newSSeq, "itemLvl":newItemLvl, "itemId":"", "itemTop":newItemTop, "useYn":"Y"};

}

else if(lvl1Map._children != undefined) {

for(var j = 0 ; j < lvl1Map._children.length ; j++){

var lvl2Map = lvl1Map._children[j];

//2레벨 항목 확인

if(lvl2Map.itemId == selectedData.itemId){

var newItemTop = "";

var newItemLvl = 0;

if(lvl2Map._children != undefined){

newItemTop = lvl2Map.itemId;

newItemLvl = parseInt(lvl2Map.itemLvl, 10) + 1;

}

else{

lvl2Map._children = new Array();

newItemTop = lvl2Map.itemId;

newItemLvl = parseInt(lvl2Map.itemLvl, 10) + 1;

}

lvl2Map._children[lvl2Map._children.length] = {"sStatus":"I", "sDelCheck":0, "sSeq":newSSeq, "itemLvl":newItemLvl, "itemId":"", "itemTop":newItemTop, "useYn":"Y"};

}

}

}

}

return sheetData;

}


//신규 생성 Tree Data Row Selected

function selectedTreeNewRow(vSheet){

var treeDataLength = searchTreeDataLength(vSheet);

var rows = vSheet.getRows();

for(var i = 0 ; i < rows.length ; i++){

var row1 = rows[i];

//1레벨 selected

if(parseInt(row1.getData().sSeq, 10) == treeDataLength){

row1.select();

}

else if(row1.getTreeChildren().length != undefined){

for(var j = 0 ; j < row1.getTreeChildren().length ; j++){

var row2 = row1.getTreeChildren()[j];

//2레벨 selected

if(parseInt(row2.getData().sSeq, 10) == treeDataLength){

row2.select();

}

else if(row2.getTreeChildren().length != undefined){

for(var k = 0 ; k < row2.getTreeChildren().length ; k++){

var row3 = row2.getTreeChildren()[k];

//3레벨 selected

if(parseInt(row3.getData().sSeq, 10) == treeDataLength){

row3.select();

}

}

}

}

}

}

}



반응형

웹사이트들을 돌아다니다보면 슬라이드 되는 배너나 공지사항등을 많이 봤을것이다.

slick라는 라이브러리를 사용하면 보다 쉽게 구현이 가능하다.

 

참고 사이트 및 lib 다운로드 : http://kenwheeler.github.io/slick/

 

  <div class="your-class" style="width:500px;height:200px;border:1px #AAAAAA solid;font-size:30pt;">
    <div>1 content</div>
    <div>2 content</div>
    <div>3 content</div>
    <div>4 content</div>
    <div>5 content</div>
    <div>6 content</div>
    <div>7 content</div>
    <div>8 content</div>
    <div>9 content</div>
    <div>10 content</div>
  </div> 

 

<script type="text/javascript" src="./slick/slick.min.js"></script>

 

  <script type="text/javascript">
    $(document).ready(function(){
      $('.your-class').slick({
        dots: true,           //아래 점을 표시
        infinite: true,        //루프 옵션
        slidesToShow: 3,   //화면 표시 수
        slidesToScroll: 2   //스크롤 이동 수
      });
    });
  </script> 

반응형

startsWith 또는 endsWith 스크립트 함수를 사용하는데 IE에서 "'endsWith' 속성이나 메서드를 지원하지 않습니다." 와 같은 스크립트 에러가 발생할때가 있다.

ECMAScript 6 부터는 startsWith 또는 endsWith 함수가 추가되었다고 하는데 안될때는 아래와 같이 prototype를 선언해주면 해결된다.

 

String.prototype.endsWith = function(str) {if (this.length < str.length) { return false; } return this.lastIndexOf(str) + str.length == this.length;};

 

참고로

startsWith 함수는 지정된 텍스트가 문자열의 시작에서 발견되면 true를 반환하고 아니면 false를 반환한다.

endsWith 함수는 지정된 텍스트가 문자열의 끝에서 발견되면 true를 반환하고 아니면 false를 반환한다.

반응형

뒤로가기 기능을 막을 때 사용한다.


history.pushState(null, null, location.href);
    window.onpopstate = function () {
    history.go(1);
};


cf) history.pushState(state, title, url)


pushState는 히스토리 엔트리를 추가하는 메서드이다. (변경을 하고자 한다면 history.replaceState(state, title, url) 사용)

첫번째 인자는 전달하고자하는 object를 설정하고 (popstate 이벤트를 발생시킨다.)

두번째인자는 브라우져 타이틀을 설정하고(아직 구현은 되지 않았다고한다.)

세번째인자는 브라우져 Url을 설정한다. (주소표시줄은 "wow"라고 적든 "test.html"이라고 적든 표시는 되지만 존재여부는 따지지않는다.)

반응형

소수점을 포함한 숫자만 입력가능한 Input 세팅

 

        $("#sample-table-1 input").each(function(){
            $(this).keyup(function(){
                if( $(this).val() != null && $(this).val() != '' ) {
                    var tmps = $(this).val().replace(/[^\.|^0(0)+|^0-9\.]/g, '');
                    /* 소수점은 하나만 입력되도록*/
                    var arr = tmps.split(".");
                    if(arr.length > 2) {
                        tmps = arr[0] + '.' + arr[1];
                    }
                    $(this).val(tmps);
                }
            });
            $(this).focusout(function() {
                if( $(this).val() != null && $(this).val() != '' ) {
                    var tmps = $(this).val().replace(/[^\.|^0(0)+|^0-9\.]/g, '');

                    /* 소수점은 하나만 입력되도록*/
                    var arr = tmps.split(".");
                    if(arr.length > 2) {
                        tmps = arr[0] + '.' + arr[1];
                    }
                    $(this).val(tmps);
                }
            });
        });

 


반응형

개발을 하다보면 품질관리 테스트중 오른쪽 마우스 클릭해서 붙여넣기를 막거나 Ctrl + V를 막을때 사용한다.

물론 그러면 안되지만 뚫을려고 마음먹으면 어떻게든 뚫을 수 있다.^-^;

 

    $(function(){
        var preventEvent = {
            "keydown" : function(e) {
                var keycode = function(e){
                    return ('which' in e ? e.which : e.keyCode)
                }(e),
                ctrl_cv = (e.ctrlKey && (keycode == 118 || keycode == 86)),
                shift_insert = (e.shiftKey && keycode == 45);
                if (ctrl_cv || shift_insert){
                    return false;
                }
            }
            ,"mousedown" : function(e) {
                var rightClick = (e.button == 2);
                if(rightClick){
                    return false;
                }
            }
            ,"contextmenu" : function(e) {
                return false;
            }
        };
        $(document).bind(preventEvent);
    }());
반응형

$("input:not(:radio)").length                         -> radio가 아닌 input 노드

$("input:radio:checked:enabled").attr("id")       -> 활성화되어있고 체크되어 있는 radio 타입의 input 노드

 

이외 :selected, :hidden, :first-child, :last-child, :only-child(형제가 없는 노드), :nth-child(n)(n번째 자식노드), :eq(n), :gt(n), :lt(n)(n보다 작은 노드),

:even(짝수번째 노드), :odd(홀수번째 노드), :contains("wow")(wow 텍스트를 포함한 노드) 등을 사용하여 원하는 노드를 찾을 수 있다.

 

반응형
 var str = "abcdefgabcdefghi";
 alert("1 row -> " + str.substring(0, 1) + " : " + str.substr(0, 1));
 alert("2 row -> " + str.substring(5, 3) + " : " + str.substr(5, 3));
 alert("3 row -> " + str.substring(5, 7) + " : " + str.substr(5, 7));

 

결과 ->

1 row -> a : a

2 row -> de : fga

3 row -> fg : fgabcde

 

substring 함수는 (자를문자열시작위치, 자를문자열종료위치)를 나타내기 때문에 substring(5, 3)과 같은 경우는 뒤에서 앞으로 찾아가 문자를 자르게 된다.

 

substr 함수는 (자를문자열시작위치, 자를문자열길이)를 나타내기 때문에 substring(5, 7)과 같은 경우는 5번재문자열에서 7문자까지 문자를 자르게 된다.

 

반응형
 var str = "abcdefgabcdefghi";
 alert(str.indexOf("cd") + " : " + str.lastIndexOf("cd"));

 

결과 -> 2 : 9

 

indexOf는 앞에서부터 찾고자하는 문자열을 찾아서 앞에서부터의 자릿수 반환

lastIndexOf는 뒤에서부터 찾고자하는 문자열을 찾아서 앞에서부터의 자릿수 반환

 

찾는 문자열이 없을 경우는 -1 반환

반응형

jquery each에서 루프를 돌면서 break 또는 continue를 걸면 스크립트 오류가 발생한다.

 

루프를 멈추고 루프밖으로 나가기 위해 break 대신에 return false 를

 

루프를 계속 지속하기 위해 continue 대신에 return true 를 사용하면 된다.

 

반응형

$("input[name='sample']") : name이 sample인 객체

 

$("input[name!='sample']") : name이 sample이 아닌 객체들(ex: okok, test, wow 등)

 

$("input[name^='sample']") : name이 sample로 시작하는 객체들(ex: sample01, sample_ok, sampleEtc 등) 

 

$("input[name*='sample']") : name이 sample을 포함하는 객체들(ex: oksample01, exsample, sample01 등)

 

$("input[name$='sample']") : name이 sample로 끝나는 객체들(ex: oksample, exsample, test_sample 등)

 

input에 다른 Selector 를 사용할 수 있고 name 대신 다른 속성들을 사용할 수 있다.

 

ex1) $("select[id$='sample']) : id가 sample로 끝나는 객체들(ex: 01_sample, 02_sample, etcsample 등)

 

ex2) $("textarea[class^='sample']) : class가 sample로 시작하는 객체들(ex: sample01, sample02, sample_etc 등)

반응형

ex) $('#test').load("./test.do", {usrId : 'tester'}, function(){alert("ending!");})

cf) $.load(url, data, callback)

 

url : 가져올 url 또는 파일명

data : 넘길 파라미터

callback : 로딩후 콜백함수

반응형

onload시 a태그에 click이벤트를 부여하여 "aClick"라는 함수를 호출하기

 

 window.onload = function () {
  var aArr = document.getElementsByTagName("A");
  for(var i = 0 ; i < aArr.length ; i++){
   aArr[i].addEventListener("click", function(){
    aClick(this.href);
   });
  }
 }

반응형

이전 주소 스크립트 :  document.referrer

현재 주소 스크립트 : location.href

반응형


<button type="button" class="btn btn-azure btn-sm btn-scroll btn-scroll-top ti-bookmark addScrap" data-type="customChart">
    <span>스크랩</span>
</button>
<!-- Modal -->
<div id="memoDialogModal" title="메모저장">
 <div>
  <textarea name="memo" id="memo" rows="5" cols="50">Test Memo</textarea>
  <button class="addScrapSave" data-type="customChart">저장</button>
 </div>
</div>

 

 

  $('.addScrap').on('click', function(){
   $('#memo').text('');
   $( "#memoDialogModal" ).dialog({
      resizable: false,
      height: 300,
      width: 500,
      modal: true,
      buttons: {
     "닫기": function() {
        $( this ).dialog( "close" );
     }
      }
    });
  });
  
  $('.addScrapSave').on('click', function(){
   var scrapUrl = window.location.pathname;
   var scrapParam = $('form[name=searchFrm]').serialize();
   var titleName =$('.mainTitle').text().trim();
   var subTitle = $('#tab-nav ul li') ? $('#tab-nav ul li.active-cr').text().trim() : '';
   var scrapAction = $(this).attr('data-type');
   var memo = $('#memo').text();

   if(subTitle)
    titleName += "-" + subTitle;

   var param = {scrapName : titleName, scrapUrl : scrapUrl, scrapParam : scrapParam, scrapAction : scrapAction , memo : memo};
   var url = '/myPage//addScrapAjax.do';

   $.ajaxSubmit(url, param, function(data){
    if(data.result){
     alert("스크랩 되었습니다.");
     $( "#memoDialogModal" ).dialog( "close" );
    }
    else
     alert("에러가 발생하였습니다.");
   });
  });

반응형

+ Recent posts