설명

javascript로 새로운 html page를 get 혹은 post 방식으로 오픈

 

방법

post

// html
<form id="post_form" name="post_form">
    <input type="text" id='param1' name='param1' value="bb">
    <input type="text" id='param2' name='param2' value="aa">
    <input type="text" id='param3' name='param3' value="oo">
</form>


// javascript
var post_form = document.post_form;
var url = '/project/post_test'
window.open('','project_post')

post_form.action = url;
post_form.method="post";
post_form.target = 'project_post' 
post_form.param1 = 'banana'
post_form.param2 = 'apple'
post_form.param3 = 'orange'

post_form.submit(); 

get

// html


// javascript
var param1_val = 'banana' 
var param2_val = 'apple' 
var param3_val = 'orange' 
window.open('/project/get_test?param1='+param1_val+'&param2='+param2_val+'&param3='+param3_val);

참고

https://milkye.tistory.com/354

내용

이벤트 발생 시점 div 에 정의된 내용을 출력 or 숨김 하고 싶은 경우

 

방법

html

<div class="row" id="test_div">
          ~~~~~
</div>

 

javascript

화면 출력
document.getElementById("test_div").style.display = "";

화면 숨김
document.getElementById("test_div").style.display = "none";

참고

https://www.w3schools.com/jsref/prop_style_display.asp

 

 

Delete 실행 시 확인창을 예제로 작성

modal 호출 시 매개변수를 포함하여 처리

 

html

매개변수 전달을 위해 modal_id를 hidden타입으로 생성

매개변수 전달을 위해 result.id 변수를 SetParamModal()함수에 전달

ID가 Delete_Modal 인 modal 생성

Close 버튼은 창 닫기

Delete 버튼은 Delete() 함수 호출

<!-- Button trigger modal -->
<input type="hidden" name="modal_id" id="modal_id">
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#Delete_Modal" onclick="SetParamModal('{{ result.id }}')">
  Delete
</button>


<!-- Modal -->
<div class="modal fade" id="Delete_Modal" tabindex="-1" role="dialog" aria-labelledby="DeleteModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="DeleteModalLabel">Delete</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        삭제 하시겠습니까 ?
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary" href="#" onclick="Delete()">Delete</button>
      </div>
    </div>
  </div>
</div>

js

SetParamModal(modal_id) : Modal 실행 시 매개변수 전달 기능

Delete() : 실제 삭제 로직 추가

<script src="./jquery-3.4.1.min.js"></script>
<script src="./bootstrapt/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="./bootstrapt/css/bootstrap.min.css" />


// modal_id 타입에 전달받은 값을 설정
// Modal 버튼 클릭 시 호출
function SetParamModal(modal_id) {

    $('#modal_id').val(modal_id);
}


// Delete
// Modal창에서 'Delete' 버튼 클릭 시 호출
function Delete() {

    //Modal 호출시 전달한 id 확인
    id = $('#modal_id').val();
    
    // Delete 로직 실행
    // 'Delete from table where id = ' + id;
    
    // Delete modal창 닫기
    $('#Delete_Modal').modal('hide');
}

팝업 화면

참고

https://getbootstrap.com/docs/4.4/components/modal/

방법

라인의 마지막 부분에 \ 을 추가한다.

// validation
$(".adjustment, .info input, .includesAndTiming input, \
    .independentAdj, .generalAdj, .executiveAdj \
    #officeExpense, #longDistanceExpense, #digitalImages, #milesReimbursment, #driveTime, #statementTranscription").keypress(function (event) {

 

참고

https://stackoverflow.com/questions/10514873/line-continuation-characters-in-javascript

html

<textarea id="textarea_summernote" name="textarea_summernote">
  textarea 내용 입력
</textarea>

javascript

html에서 생성한 textarea_summernote textarea를 summernote()를 사용하여 초기화 진행

이미지 파일 처리를 위해 onImageUpload 함수 등록

uploadSummernoteImageFile 함수에서 첨부한 파일 정보를 ajax를 이용하여 flask로 전달하여 저장소에 저장

setSummernoteValue 함수는 Summernote에 값을 추가하는 예시

// summernote 초기화
$(function () {
    // Summernote
    $('#textarea_summernote').summernote({
        callbacks : {
            // 이미지 첨부하는 부분
            onImageUpload : function(files){
                uploadSummernoteImageFile(files[0],this);
            },
            onPaste : function(e) {
                var clipboardData = e.originalEvent.clipboardData;

                if(clipboardData && clipboardData.items && clipboardData.items.length){
                    var item = clipboardData.items[0];
                    if(item.kind === 'file' && item.type.indexOf('image/') !== -1){
                        e.preventDefault();
                    }
                }
            }
        }
    });  
});


// summernote - 이미지 파일 업로드
function uploadSummernoteImageFile(file, editor){

    // 프로젝트 코드
    var project_code = 'test'
    
    var data = new FormData();
    data.append('file',file);
    data.append('project_code', project_code);

    //file 정보를 python으로 전달
    $.ajax({
        data: data,
        type : "POST",
        url : "/test/uploadSummernoteImageFile",
        contentType : false,
        processData : false,
        success : function(data){
            alert('File Upload Success')
            $(editor).summernote('insertImage', data.filepath);
        }
    });
}


function setSummernoteValue(value) {

    // value가 문자열인 경우
    $('#textarea_summernote').summernote('insertText', value);
    
    // value가 html 태크 형태인 경우
    $('#textarea_summernote').summernote('pasteHTML', value);
}

python

프로젝트 코드(또는 메뉴등의 그룹)별 파일을 저장하기 위해 폴더에 서비스 코드 추가

파일명이 겹치지 않도록 파일명 앞에 현시간을 추가

@project_blueprint.route('test/uploadSummernoteImageFile', methods =['POST'])
@login_required
def project_test_uploadSummernoteImageFile():

    try :
        file = request.files['file']
        project_code = request.form['project_code']
        default_path = 'test/img/'

        host_path = default_path + project_code + '/'
        if not os.path.exists(host_path):
            os.mkdir(host_path)

        now_date = datetime.datetime.now()
        prefix_date = now_date.strftime('%Y%m%d_%H%M%S_')

        img_name = host_path + prefix_date + file.filename
        file.save(img_name)

        return jsonify(filepath = img_name[3:])

    except (RuntimeError, TypeError, NameError, SQLAlchemyError) as e:
        print("#### img upload Failed !! " + str(e))

        return jsonify(message=str(e))

참고

https://summernote.org/deep-dive/#pastehtml

html

<table id="test_table" class="table table-bordered">
  <tbody id="test_tbody">
    <tr>
      <td>title</td>
      <td>id</td>
      <td>name</td>
      <td>detail</td>
    </tr>
    <tr>
      <td>abs</td>
      <td>1</td>
      <td>Lee</td>
      <td>888</td>
    </tr>
  </tbody>
</table>

javascript

첫번째 row(tr)의 값을 조회
document.getElementById("test_table").getElementsByTagName("tr")[0].innerHTML
document.getElementById("test_tbody").getElementsByTagName("tr")[0].innerHTML
첫번째 row(tr)의 값을 'asdf'로 변경
document.getElementById("test_table").getElementsByTagName("tr")[0].innerHTML = 'asdf'

첫번째 row(tr)의 첫번째 td값을 조회
document.getElementById("report_tbody").getElementsByTagName("tr")[0].getElementsByTagName("td")[0].innerHTML
첫번째 row(tr)의 두번째 td값을 조회
document.getElementById("report_tbody").getElementsByTagName("tr")[0].getElementsByTagName("td")[1].innerHTML
첫번째 row(tr)의 첫번째 td값을 'qwer'로 변경
document.getElementById("report_tbody").getElementsByTagName("tr")[0].getElementsByTagName("td")[0].innerHTML = 'qwer'

참고

https://stackoverflow.com/questions/8508262/how-to-select-td-of-the-table-with-javascript

설명

textarea에 image 및 tag 적용이 되지 않음

적용이 불가능하지는 않은듯하나 예외 사항이 많아 적용이 쉽지 않음

div contentEditable="true" 형태를 사용하여 image 및 text를 함께 작성

div contentEditable 형태는 form 형태로 전달하기 힘들기 때문에 hidden text를 사용하여 db에 내용을 전달

Page를 불러 올때 hidden 형태의 타입의 값을 div contentEditable 부분에 가져와서 보여줌

 

html

DB 에서 데이터를 조회하여 templates에 result.content_detail 값을 전달하여 처리하는 형태

content_detail은 hidden형태로 값을 전달하는 중간 역할

content_detail_edit는 실제로 데이터(이미지 및 텍스트)를 화면에 출력하는 역할

 

content_detail_image는 file 타입으로 이미지의 정보를 처리

content_img_width는 이미지의 width정보를 전달하기 위한 용도

<div class="form-group col-md-10">
    <div class="input-group">
        <div class="input-group-prepend iw-100" data-toggle="tooltip" data-container="body" title="content 내용">
            <button type="button" class="btn btn-warning iw-100" onclick="expandText()">Content *</button>
        </div>
        <input type="hidden" name="content_detail" id="content_detail" value = "{{ result.content_detail }}"/>
        <div contentEditable="true" style="min-height: 100px;height: 100%;max-width: 100%;white-space: pre-wrap; word-break: break-word;"class="form-control" id="content_detail_edit" required> </div>
    </div>
</div>

<div class="form-group col-md-2">
    <div class="input-group">
        <div class="custom-file">
            <input type="file" class="custom-file-input" id="content_detail_image" name="content_detail_image">
            <label class="custom-file-label" for="content_detail_image">Choose file</label>
        </div>
        <div class="input-group-append">
            <span class="input-group-text" onclick="goContent_Detail_Image();">Upload</span>
        </div>
    </div>
    Image Width <input style="width: 75px;" type="text" name="content_img_width" class="form-control"  id="content_img_width" value="800" />
</div>

javascript

function 내부에서 bsCustomFileInput.init();를 호출하여 파일 객체 초기화 진행

function 내부에서 hidden type의 데이터를 contentDeitable 타입의 값에 복사하여 page에 출력시 사용

 

goContent_Detail_Image함수에서

file객체의 정보를 ajax 형태로 python으로 전달

python으로 서버에 이미지 생성 성공시 저장된 위치 및 파일명을 기반으로, templates의 content_detail 및 content_detail_edit에 이미치 tag를 추가하여 출력

이미지는 content_img_width에 설정된 값으로 생성(너무 크게 생성되는것을 방지하기 위해 1024를 max로 처리)

 

goContent_Edit함수에서

content_detail_edit에 수정한 내용을 DB에 저장할 때는 content_detail로 값을 변경하여 전달

<!-- Tempusdominus Bootstrap 4 -->
<link rel="stylesheet" href="/static/plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css">

<!-- jQuery -->
<script src="/static/plugins/jquery/jquery.min.js"></script>
<!-- Bootstrap 4 -->
<script src="/static/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- bs-custom-file-input -->
<script src="/static/plugins/bs-custom-file-input/bs-custom-file-input.min.js"></script>


$(function () {
    // File 객체 초기화
    bsCustomFileInput.init();
  
    // hidden type의 데이터를 contentEditable 타입의 값에 복사
    Src_Val = $('#content_detail').val()
    document.getElementById('content_detail_edit').innerHTML = Src_Val;
    document.getElementById("content_detail_edit").focus();
});


function goContent_Detail_Image(){
    
    let content_id = $('#content_id').val()
    let file = $('#content_detail_image')[0].files[0]

    let form_data = new FormData()
    form_data.append("id_give", content_id)
    form_data.append("file_give", file)

    // Image를 서버에 저장
    $.ajax({
        url:'/content/detail_image',
        type:'POST',
        data: form_data,
        cache: false,
        contentType: false,
        processData: false,
        success: function(data){
            showAlert('content detail image insert successful!!!', data.filename, 2, 2000);

            // 이미지 최대 width는 1024로 제한
            img_width = $('#content_img_width').val()
            if ( img_width > 1024 ) img_width = 1024;

            Src_Val = $('#content_detail').val()
            Change_Val = Src_Val + '<br> <img width = "' + img_width + '" src="/static/img/content/' + data.filename + '">' 

            document.getElementById('content_detail').innerHTML = Change_Val;
            document.getElementById('content_detail_edit').innerHTML = Change_Val;

        },
        error: function(xhr, ajaxOptions, thrownError) {
            var fail_title = "content detail img upload Failed!!";
            var fail_msg = '';
            var err_msg = JSON.parse(xhr.responseText);

            if (thrownError == 'UNKNOWN'){
                fail_msg = err_msg.message + ' (' + xhr.status + ')'
            } else {
                fail_msg = err_msg.message + ' (' + thrownError + ',' + xhr.status + ')';
            }

            showAlert(fail_title,fail_msg,3,1500);
        }
    });
    return false;
}


function goContent_Edit(){
// ** Content 수정 ** //

    // content detail text 전환
    Src_Val = document.getElementById('content_detail_edit').innerHTML;
    $('#content_detail').val(Src_Val);

    var param = $('#content_form').serialize();

    // content 수정 요청
    $.ajax({
        url:'/content/edit',
        type:'POST',
        data: param,
        success: function(data){
            showAlert('content Edit Successful!!!', data.message, 2, 2000);
        },
        error: function(xhr, ajaxOptions, thrownError) {
            var fail_title = "content edit Failed!!";
            var fail_msg = '';
            var err_msg = JSON.parse(xhr.responseText);

            if (thrownError == 'UNKNOWN'){
                fail_msg = err_msg.message + ' (' + xhr.status + ')'
            } else {
                fail_msg = err_msg.message + ' (' + thrownError + ',' + xhr.status + ')';
            }

            showAlert(fail_title,fail_msg,3,1500);
        }
    });
    return false;
};

python

이미지 파일명은 content_id + prefix_date + filename을 조합하여, 이미지 content별 구분과 등록 순서를 확인 가능하도록 네이밍 처리함

이미지를 서버에 저장한 이후 화면에 이미지를 출력하기 위해 파일명을 리턴

from werkzeug import secure_filename

@bts_blueprint.route('content/detail_image', methods=['POST'])
def content_detail_image():

    print("##  content_detail_image  ##")

    try:
        file = request.files['file_give']
        content_id = request.form['id_give']
        #extention = file.filename.split('.')[-1]

        UploadPath = 'static/img/content/'
        
        now_date = datetime.datetime.now()
        prefix_date = now_date.strftime('_%Y%m%d_%H%M%S_')
        
        ImgFullname = UploadPath + content_id + prefix_date + file.filename
        
        #file.save(UploadPath, secure_filename(file.filename))
        file.save(ImgFullname)

        return jsonify(filename=content_id + prefix_date + file.filename), 200

    except (RuntimeError, TypeError, NameError, SQLAlchemyError) as e:
        print("#### content detail img upload Failed !! " + str(e))

        return jsonify(message=str(e)), 1002

참고

https://velog.io/@wrs0707/%EB%82%98%ED%99%80%EB%A1%9C%EC%9D%BC%EA%B8%B0%EC%9E%A5-%EB%A7%8C%EB%93%A4%EA%B8%B0

 

https://blog.naver.com/ynskoh/221064660966

현재 Page에서 열기

var OpenURL = 'https://openurl.co.kr';

window.location = OpenURL;

새탭에서 Page 열기

var OpenURL = 'https://openurl.co.kr';

window.open(OpenURL);

<a>~</a> 태그의 속성

_blank: 새 탭, 창

_self: 현재 탭, 창

_parent: 부모 탭, 창
_top: 최상위 탭, 창

<a href="http://tistory.com/" target="_blank">새 창, 탭 열기</a>
<a href="http://tistory.com/" target="_self">현재 창, 탭 열기</a>
<a href="http://tistory.com/" target="_parent">부모 탭, 창</a>
<a href="http://tistory.com/" target="_top">최상위 탭, 창</a>

today, tomorrow 날짜구하기

const today = new Date();
const tomorrow = new Date();

// Add 1 Day
tomorrow.setDate(today.getDate() + 1);

입력한 날짜(yyyyMMdd)가 유효한 날짜인지 검사

function is_valid_date(date_str)
{
    var yyyyMMdd = String(date_str);
    var year = yyyyMMdd.substring(0,4);
    var month = yyyyMMdd.substring(4,6);
    var day = yyyyMMdd.substring(6,8);

    if (!is_number(date_str) || date_str.length!=8)
        return false;

    if (Number(month)>12 || Number(month)<1)
        return false;

    if (Number(last_day(date_str))<day)
        return false;

    return true;
}

yyyy-MM-dd 날짜 문자열을 Date형으로 반환

function to_date2(date_str)
{
    var yyyyMMdd = String(date_str);
    var sYear = yyyyMMdd.substring(0,4);
    var sMonth = yyyyMMdd.substring(5,7);
    var sDate = yyyyMMdd.substring(8,10);

    //alert("sYear :"+sYear +"   sMonth :"+sMonth + "   sDate :"+sDate);
    return new Date(Number(sYear), Number(sMonth)-1, Number(sDate));
}

Date형을 yyyyMMdd형의 문자열로 변환

function get_date_str(date)
{
    var sYear = date.getFullYear();
    var sMonth = date.getMonth() + 1;
    var sDate = date.getDate();

    sMonth = sMonth > 9 ? sMonth : "0" + sMonth;
    sDate  = sDate > 9 ? sDate : "0" + sDate;
    return sYear + sMonth + sDate;
}

주어진 날짜가 윤년인지를 검사

function is_leap_year(date_str)
{
    var year = date_str.substring(0,4);
    if (year%4 == 0)
    {
        if (year%100 == 0)
            return (year%400 == 0);
        else
            return true;
    }
    else
        return false;
}

주어진 날짜(yyyyMMdd, yyyyMM) 그 달의 마지막 날짜를 반환

function last_day(date_str)
{
    var yyyyMMdd = String(date_str);
    var days = "31";
    var year = yyyyMMdd.substring(0,4);
    var month = yyyyMMdd.substring(4,6);

    if (Number(month) == 2)
    {
        if (is_leap_year(year+month+"01"))
            days = "29";
        else
            days = "28";
    }
else if (Number(month) == 4 || Number(month) == 6 || Number(month) == 9 || Number(month) == 11)
        days = "30";

    return days;
}

오늘 날짜 중 연도 반환

function get_today_year()
{
    var today = new Date();
    return today.getYear();
}

오늘 날짜 중 Month반환. format: MM

function get_today_month()
{
    var today = new Date();
    return (today.getMonth()+1) > 9 ?  (today.getMonth()+1) : "0" + (today.getMonth()+1)
}

참고

https://java119.tistory.com/76

 

[JavaScript] 날짜 관련 유용 함수 총 정리(feat.String to Date)

입력한 날짜(yyyyMMdd)가 유효한 날짜인지 검사 function is_valid_date(date_str) { var yyyyMMdd = String(date_str); var year = yyyyMMdd.substring(0,4); var month = yyyyMMdd.substring(4,6); var day = yy..

java119.tistory.com

html

<table id="factory_table" class="table" style="margin-top: 20px;">
	<colgroup>
		<col width="20%"/>
		<col width="10%"/>
		<col width="30%"/>
		<col width="30%"/>
		<col width="10%"/>
	</colgroup>
	
	<thead>
		<tr>
			<th>이름(설비)</th>
			<th>대수</th>
			<th>기계 및 컨트롤러 정보</th>
			<th>공정명</th>
			<th></th>
		</tr>
	</thead>

	<tbody id="factory_tbody">
		<tr>
			<td> <input type="text" class="form-control" placeholder="설비명">  </td>
			<td> <input type="number" class="form-control" placeholder="설치 대수" onkeypress="return event.charCode >= 48 && event.charCode <= 57">  </td>
			<td> <input type="text" class="form-control" placeholder="기계 및 컨트롤러 정보">  </td>
			<td> <input type="text" class="form-control" placeholder="공정명">  </td>
			<td></td>
		</tr>
	</tbody>
</table>

Table 행 추가

// 하나의 Row 입력
var rowItem = "<tr>"
rowItem += "<td> <input type='text' class='form-control' placeholder='설비명'> </td>"
rowItem += "<td> <input type='number' class='form-control' placeholder='설치 대수' onkeypress='return event.charCode >= 48 && event.charCode <= 57'> </td>"
rowItem += "<td> <input type='email' class='form-control' placeholder='기계 및 컨트롤러 정보'> </td>"
rowItem += "<td> <input type='text' class='form-control' placeholder='공정명'> </td>"
rowItem += "<td> <button type='button' class='btn btn-danger'> <i class='fa fa-minus'></i> </button> </td>"
rowItem += "</tr>"
$('#factory_table').append(rowItem)




// Table 행을 모두 삭제 후 리스트 형식 입력 ( 예제와 별도 형식 )
var TableRowsList = ["'a','b','c','d','e'","'1','2','3','4','5'",,,,]  <-- Table rows list가 들어 있다는 가정..

$('#factory_table').remove();

var rowItem = '<tr>'
rowItem += '<th>이름(설비)</th>'
rowItem += '<th>대수</th>'
rowItem += '<th>기계 및 컨트롤러 정보</th>'
rowItem += '<th>공정명</th>'
rowItem += '<th></th>'
rowItem += '</tr>'
$('#factory_table').append(rowItem)
            
for(key in TableRowsList ){
    RowList = TableRowsList[key].split(',')
    var rowItem = '<tr>'
    rowItem += '<td> ' + RowList[1] + ' </td>'
    rowItem += '<td> ' + RowList[2] + ' </td>'
    rowItem += '<td> ' + RowList[3] + ' </td>'
    rowItem += '<td> ' + RowList[4] + ' </td>'
    rowItem += '<td> ' + RowList[5] + ' </td>'
    rowItem += '</tr>'
    $('#factory_table').append(rowItem)
}

Table 행 삭제

$('#factory_table').on("click", "button", function() {
    $(this).closest("tr").remove()
});

입력된 Table 행 데이터 가져오기

$('#factory_tbody tr').each(function () {
	var cellItem = $(this).find(":input")
	var itemObj = new Object()
	itemObj.title = cellItem.eq(0).val()
	itemObj.count = cellItem.eq(1).val()
	itemObj.info = cellItem.eq(2).val()
	itemObj.name = cellItem.eq(3).val()
})

참고

https://elfinlas.github.io/2017/12/25/devnote01/

 

12월 18일 개발일지 (HTML Table의 행을 동적으로 처리하기 with jQuery)

HTML에서 Table 요소 처리이번에 제가 만드는 사내정보시스템을 이번에 저희 회사에도 도입을 하게 되면서, 회사에 특화된 기능을 개발하게 되었습니다.그런데 이번에 Html의 테이블 요소를 다루게

elfinlas.github.io

 


to Top