Files
sam-kd/bending/write_form.php

1598 lines
72 KiB
PHP
Raw Normal View History

<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
// 첫 화면 표시 문구
$title_message = '절곡바라시 기초자료';
?>
<title> <?=$title_message?> </title>
<link rel="stylesheet" href="css/style.css?v=<?=time()?>">
</head>
<body>
<?php
$option = isset($_REQUEST['option']) ? $_REQUEST['option'] : '';
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
$header = isset($_REQUEST['header']) ? $_REQUEST['header'] : '';
$partIndex = isset($_REQUEST['partIndex']) ? $_REQUEST['partIndex'] : '';
$tablename = 'bending';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
$num = isset($_REQUEST["num"]) ? $_REQUEST["num"] : 0;
// 조회일 경우
if ($num > 0 && $mode == 'view' ) {
try {
$sql = "SELECT * FROM " . $DB . "." . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
include '_row.php';
} catch (PDOException $Exception) {
print "오류: " . $Exception->getMessage();
}
$mode = 'view';
$title_message = '절곡바라시 기초자료 조회';
}
else if ($num > 0 && $mode == 'modify' ) {
try {
$sql = "SELECT * FROM " . $DB . "." . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
include '_row.php';
} catch (PDOException $Exception) {
print "오류: " . $Exception->getMessage();
}
$mode = 'modify';
$title_message = '절곡바라시 기초자료 수정';
}
else if ($num > 0 && $mode == 'copy' ) {
try {
$sql = "SELECT * FROM " . $DB . "." . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
include '_row.php';
} catch (PDOException $Exception) {
print "오류: " . $Exception->getMessage();
}
$title_message = '(데이터복사) 절곡바라시 기초자료 등록';
}
else if ($mode == 'write' ) { // 전달받은 새로 작성하는 경우
include '_request.php';
$imgdata = '';
// URL 파라미터에서 배열 데이터 받기
$inputList = isset($_REQUEST['inputList']) ? json_decode($_REQUEST['inputList'], true) : [];
$bendingrateList = isset($_REQUEST['bendingrateList']) ? json_decode($_REQUEST['bendingrateList'], true) : [];
$sumList = isset($_REQUEST['sumList']) ? json_decode($_REQUEST['sumList'], true) : [];
$colorList = isset($_REQUEST['colorList']) ? json_decode($_REQUEST['colorList'], true) : [];
$AList = isset($_REQUEST['AList']) ? json_decode($_REQUEST['AList'], true) : [];
// 이미지는 부모창의 번호를 기준으로 가져온다.
if(intval($num) > 0) {
$sql = "SELECT * FROM " . $DB . "." . $tablename . " WHERE num=?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_STR);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
$imgdata = $row['imgdata'];
}
// 부모창에서 전달받은 partIndex (부품 인덱스)
$partIndex = isset($_REQUEST['partIndex']) ? $_REQUEST['partIndex'] : '';
$author = isset($user_name) ? $user_name : '';
$registration_date = date('Y-m-d'); // 현재일자 기록
$title_message = '(데이터 다른이름으로 저장) 절곡바라시 기초자료 등록';
} else {
include '_request.php';
$mode = 'insert';
$memo = '';
$imgdata = '';
$itemName = '';
$inputList = [];
$bendingrateList = [];
$sumList = [];
$colorList = [];
$AList = [];
$author = $user_name ?? '';
$registration_date = date('Y-m-d'); // 현재일자 기록
// mode값에 get 이면 각 부품에서 이 코드를 호출하는 것이다.
if($mode == 'get') {
// 삽입으로 설정함.
$mode = 'insert';
$item_sep = isset($_REQUEST['item_sep']) ? $_REQUEST['item_sep'] : '';
$model_UA = isset($_REQUEST['model_UA']) ? $_REQUEST['model_UA'] : '';
$item_bending = isset($_REQUEST['item_bending']) ? $_REQUEST['item_bending'] : '';
$itemName = isset($_REQUEST['itemName']) ? $_REQUEST['itemName'] : '';
$item_spec = isset($_REQUEST['item_spec']) ? $_REQUEST['item_spec'] : '';
$imgdata = isset($_REQUEST['imgdata']) ? $_REQUEST['imgdata'] : '';
$exit_direction = isset($_REQUEST['exit_direction']) ? $_REQUEST['exit_direction'] : '';
$front_bottom_width = isset($_REQUEST['front_bottom_width']) ? $_REQUEST['front_bottom_width'] : '';
$rail_width = isset($_REQUEST['rail_width']) ? $_REQUEST['rail_width'] : '';
$box_width = isset($_REQUEST['box_width']) ? $_REQUEST['box_width'] : '';
$box_height = isset($_REQUEST['box_height']) ? $_REQUEST['box_height'] : '';
}
}
if(empty($author)) {
$author = $user_name ?? '';
}
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<input type="hidden" id="mode" name="mode" value="<?=$mode?>">
<input type="hidden" id="num" name="num" value=<?=$num?>>
<input type="hidden" id="tablename" name="tablename" value=<?=$tablename?>>
<input type="hidden" id="update_log" name="update_log" value=<?=$update_log?>>
<input type="hidden" id="header" name="header" value="<?=$header?>">
<input type="hidden" id="imgdata" name="imgdata" value="<?=$imgdata?>">
<div class="container-fluid">
<div class="card">
<div class="card-header text-center">
<div class="d-flex p-1 mb-1 justify-content-center align-items-center ">
<h4><?=$title_message?></h4> &nbsp; &nbsp; &nbsp; &nbsp;
<?php if($mode =='view') { ?>
<button type="button" class="btn btn-dark btn-sm me-1" onclick="location.href='write_form.php?mode=modify&num=<?=$num?>&tablename=<?=$tablename?>';"> <i class="bi bi-pencil-square"></i> 수정 </button>
<button id="copyBtn" class="btn btn-primary btn-sm me-1" type="button"><i class="bi bi-copy"></i> 복사</button>
<button id="deleteBtn" class="btn btn-danger btn-sm me-1" type="button"><i class="bi bi-trash2"></i> 삭제</button>
<?php } ?>
<?php if($mode!=='view') { ?>
<button id="saveBtn" class="btn btn-dark btn-sm me-1 " type="button">
<? if((int)$num>0) print ' <i class="bi bi-hdd-fill"></i> 저장'; else print ' <i class="bi bi-hdd-fill"></i> 저장'; ?></button>
<?php } ?>
<button type="button" class="btn btn-outline-dark btn-sm me-2" id="showlogBtn"> H</button>
<button class="btn btn-secondary btn-sm ms-3" onclick="self.close();"> &times; 닫기 </button>
</div>
</div>
<div class="card-body">
<div class="container-fluid">
<div class="card">
<div class="card-body">
<div class="row mt-3">
<div class="col-sm-9">
<div class="card">
<div class="card-header text-center">
<table class="table table-bordered align-middle">
<tr>
<!-- 1: 등록일, SLAT형태, 절곡품 그룹 -->
<td class="text-end align-middle fw-bold" style="width: 8%;">등록일</td>
<td style="width: 13%;">
<input type="date" id="registration_date" class="form-control noborder-input w110px" name="registration_date" value="<?= $registration_date ?>" autocomplete="off">
</td>
<td class="text-end align-middle fw-bold" style="width: 8%;">형태</td>
<td class="w250px">
<div class="d-flex justify-content-start">
<input type="radio" id="screenUse" name="item_sep" value="스크린" <?php if (empty($item_sep) || $item_sep == '스크린') echo 'checked'; ?> class="me-1">
<label for="screenUse" class="me-2">스크린</label>
<input type="radio" id="steelStrutUse" name="item_sep" value="철재" <?php if ($item_sep == '철재') echo 'checked'; ?> class="me-1">
<label for="steelStrutUse">철재</label>
</div>
</td>
<td class="text-end align-middle fw-bold" style="width: 10%;">인정/비인정</td>
<td class="w150px">
<input type="radio" id="screenUseUA" name="model_UA" value="인정" <?php if (empty($model_UA) || $model_UA == '인정') echo 'checked'; ?> class="me-1">
<label for="screenUseUA" class="me-2">인정</label>
<input type="radio" id="steelStrutUseUA" name="model_UA" value="비인정" <?php if ($model_UA == '비인정') echo 'checked'; ?> class="me-1">
<label for="steelStrutUseUA">비인정</label>
</td>
<td class="text-end align-middle fw-bold" style="width: 8%;">절곡품 그룹</td>
<td colspan="1" class="text-start">
<?php
// 예: getCategoryByName($parentName) 함수가 존재하며,
// '절곡물'이라는 2단계 카테고리의 자식(3단계) 카테고리 이름 배열을 리턴한다.
$l3_list = getCategoryByName('스크린','절곡물');
?>
<select id="item_bending" name="item_bending" class="form-select w-auto mx-1" style="font-size: 0.7rem; height: 30px;">
<option value="">(절곡물)</option>
<?php foreach($l3_list as $itemVal): ?>
<option
value="<?= htmlspecialchars($itemVal, ENT_QUOTES, 'UTF-8') ?>"
<?= ($item_bending === $itemVal) ? 'selected' : '' ?>>
<?= htmlspecialchars($itemVal, ENT_QUOTES, 'UTF-8') ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<td class="text-end align-middle fw-bold w50px">폭합</td>
<td colspan="1">
<input type="text" id="widthsum" class="form-control text-end w50px" name="widthsum" value="<?= $widthsum ?>" readonly autocomplete="off">
</td>
<td class="text-end align-middle fw-bold">품명</td>
<td>
<input type="text" id="itemName" class="form-control noborder-input text-start" name="itemName" value="<?= $itemName ?>" autocomplete="off">
</td>
<td class="text-end align-middle fw-bold">규격(가로*세로)</td>
<td>
<input type="text" id="item_spec" class="form-control noborder-input text-start " name="item_spec" value="<?= $item_spec ?>" autocomplete="off">
</td>
<td class="text-end align-middle fw-bold">재질</td>
<td>
<select id="material" class="form-select w-auto" name="material" style="font-size: 0.7rem; height: 30px;">
<?php
$options = ['(선택)', 'EGI 1.15T', 'EGI 1.55T', 'SUS 1.2T', 'SUS 1.5T'];
foreach ($options as $option) {
$selected = ($material === $option) ? 'selected' : '';
echo "<option value=\"" . htmlspecialchars($option, ENT_QUOTES, 'UTF-8') . "\" $selected>$option</option>";
}
?>
</select>
</td>
</tr>
<tr>
<td colspan="8" class="text-end ">
<div class="d-flex justify-content-start align-items-center">
(케이스 부품관련 영역) <span class="text-dark ms-5 me-2"></span>점검구 방향</span>
<select id="exit_direction" class="form-select w120px" name="exit_direction" style="font-size: 0.7rem; height: 30px;">
<option value="">(선택)</option>
<option value="양면 점검구" <?php if ($exit_direction === '양면 점검구') echo 'selected'; ?>>양면 점검구</option>
<option value="후면 점검구" <?php if ($exit_direction === '후면 점검구') echo 'selected'; ?>>후면 점검구</option>
<option value="밑면 점검구" <?php if ($exit_direction === '밑면 점검구') echo 'selected'; ?>>밑면 점검구</option>
</select>
<span class="text-dark ms-3 me-1">케이스 너비</span>
<input type="text" id="box_width" class="form-control text-end w50px" name="box_width" value="<?= $box_width ?>" autocomplete="off">
<span class="text-dark ms-3 me-1">케이스 높이</span>
<input type="text" id="box_height" class="form-control text-end w50px" name="box_height" value="<?= $box_height ?>" autocomplete="off">
<span class="text-dark ms-3 me-1">전면부 치수</span>
<input type="text" id="front_bottom_width" class="form-control text-end w50px" name="front_bottom_width" value="<?= $front_bottom_width ?>" autocomplete="off">
<span class="text-dark ms-3 me-1">레일폭</span>
<input type="text" id="rail_width" class="form-control text-end w50px" name="rail_width" value="<?= $rail_width ?>" autocomplete="off">
</div>
</td>
</tr>
<tr>
<td class="text-end align-middle fw-bold">작성자</td>
<td colspan="1">
<input type="text" id="author" class="form-control noborder-input text-start" name="author" value="<?= $author ?>" autocomplete="off">
</td>
<td class="text-end align-middle fw-bold">품목 검색어</td>
<td colspan="1">
<input type="text" id="search_keyword" class="form-control noborder-input text-start" name="search_keyword" value="<?= $search_keyword ?>" autocomplete="off">
</td>
<td class="text-end align-middle fw-bold">비고</td>
<td colspan="3">
<input type="text" id="memo" class="form-control noborder-input text-start" name="memo" value="<?= $memo ?>" autocomplete="off">
</td>
</tr>
</table>
</div>
<div class="card-body">
<div class="row">
<div class="table-container">
<table class="table table-bordered" id="dynamicTable">
<tbody id="tableBody">
<!-- 기본적으로 상태로 두고, JS로 데이터를 추가 -->
</tbody>
</table>
</div>
</div>
<div class="d-flex mt-2 mb-2">
<button type="button" class="btn btn-secondary btn-sm me-2" id="emptyColumnBtn">모든칸 비우기</button>
<button type="button" class="btn btn-success btn-sm me-2" id="addColumnBtn">마지막 열추가</button>
<button type="button" class="btn btn-danger btn-sm" id="removeColumnBtn">마자막 열삭제</button>
</div>
</div>
</div>
</div>
<div class="col-sm-3" style="padding : 4px;">
<!-- 그리기 컨트롤 -->
<div class="d-flex align-items-center mb-2" style="width:260px;">
<?php if($mode!=='view') : ?>
<button id="openEditorBtn" type="button" class="btn btn-outline-dark btn-sm me-2 viewNoBtn">그리기</button>
<?php else: ?>
<div class="text-muted">
<i class="bi bi-info-circle"></i> 조회 모드, 그리기 기능 불가
</div>
<?php endif; ?>
</div>
<!-- 이미지 표시 영역 (수정된) -->
<div class="card mb-3">
<div class="card-body">
<div class="image-container mb-3" style="position: relative;">
<?php
// bending 테이블의 imgdata 값 사용
$imgUrl = '';
if (!empty($imgdata)) {
// 이미지 파일이 실제로 존재하는지 확인
$imagePath = $_SERVER['DOCUMENT_ROOT'] . '/bending/img/' . $imgdata;
if (file_exists($imagePath)) {
$imgUrl = '/bending/img/' . $imgdata;
} else {
// 기존 경로도 확인
$imagePath2 = $_SERVER['DOCUMENT_ROOT'] . '/bending/img/' . $imgdata;
if (file_exists($imagePath2)) {
$imgUrl = '/bending/img/' . $imgdata;
}
}
}
?>
<?php if (!empty($imgUrl)): ?>
<img
id="targetImage"
src="<?= htmlspecialchars($imgUrl) ?>"
class="img-thumbnail img-fluid"
alt="편집할 이미지"
style="max-width:350px; cursor:pointer; display: block;"
>
<?php else: ?>
<p class="text-muted">이미지가 없습니다.</p>
<?php endif; ?>
<div class="paste-overlay" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0, 123, 255, 0.8); color: white; padding: 10px 15px; border-radius: 5px; z-index: 1000; text-align: center; font-size: 14px;">
<i class="bi bi-clipboard-plus"></i>
<span>Ctrl+V로 이미지 붙여넣기</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<!-- 다이얼로그(편집기) 마크업: imageEditor.js 호출 참조 -->
<dialog id="editorDialog">
<div id="editorHeader">
<h5>이미지 편집기</h5>
<button id="applyBtn" class="btn btn-success btn-sm">적용하기</button>
<button type="button" class="btn-close" aria-label="닫기" id="closeEditorBtn"></button>
</div>
<!-- 툴바 -->
<div id="editorToolbar">
<button id="polyBtn" class="btn btn-outline-primary toolbar-btn" title="폴리라인"><i class="bi bi-vector-pen"></i></button>
<button id="freeBtn" class="btn btn-outline-primary toolbar-btn" title="자유선"><i class="bi bi-brush"></i></button>
<button id="lineBtn" class="btn btn-outline-primary toolbar-btn" title="직선 (L키)"><i class="bi bi-slash-lg"></i></button>
<button id="textBtn" class="btn btn-outline-primary toolbar-btn" title="문자입력"><i class="bi bi-type"></i></button>
<button id="eraserBtn" class="btn btn-outline-warning toolbar-btn" title="지우개"><i class="bi bi-eraser-fill"></i></button>
<button id="selectBtn" class="btn btn-outline-secondary toolbar-btn" title="객체선택"><i class="bi bi-cursor-text"></i></button>
<label class="form-check-label" style="font-size: 0.9em; font-weight: 500; cursor: pointer;">
<label style="font-size: 1.4em; font-weight: 500; cursor: pointer; margin-right:100px;">
<input class="form-check-input" type="checkbox" id="rightAngle" checked style="cursor: pointer; z-index: 10; position: relative;">
직각 고정
</label>
<button id="clearBtn" class="btn btn-outline-danger btn-sm ms-auto">전체 지우기</button>
</div>
<!-- 지우개 크기 & 색상 -->
<div id="editorToolbar2" class="d-flex align-items-center px-3 pb-2">
<div class="btn-group" role="group" id="colorPicker">
<button type="button" class="btn color-btn active" data-color="#000000" style="background:#000;"></button>
<button type="button" class="btn color-btn" data-color="#ff0000" style="background:#f00;"></button>
<button type="button" class="btn color-btn" data-color="#0000ff" style="background:#00f;"></button>
<button type="button" class="btn color-btn" data-color="#00aa00" style="background:#0a0;"></button>
<button type="button" class="btn color-btn" data-color="#ff8800" style="background:#f80;"></button>
<button type="button" class="btn color-btn" data-color="#800080" style="background:#808;"></button>
<button type="button" class="btn color-btn" data-color="#888888" style="background:#888;"></button>
</div>
<label class="mb-0 me-2">지우개 크기</label>
<input type="range" class="form-range me-2" id="eraserRange" min="5" max="100" step="1" value="20">
<span id="eraserSizeLabel" class="fw-bold">20</span>px
</div>
<!-- 캔버스 영역 -->
<div id="editorBody">
<canvas id="c" width="370" height="300"></canvas>
</div>
</dialog>
<!-- 모듈 스크립트 -->
<script type="module">
console.log('=== 모듈 스크립트 로드 시작 ===');
let openImageEditor;
// 즉시 실행 함수로 감싸서 await 사용
(async function() {
try {
const module = await import('/js/imageEditor.js');
openImageEditor = module.openImageEditor;
console.log('openImageEditor 함수 import 완료:', typeof openImageEditor);
console.log('openImageEditor 함수:', openImageEditor);
// 전역 변수로 설정하여 다른 함수에서 접근 가능하도록 함
window.openImageEditor = openImageEditor;
console.log('openImageEditor를 전역 변수로 설정 완료');
} catch (error) {
console.error('모듈 로드 실패:', error);
return;
}
})();
// 전역 함수로 선언하여 loadForm에서 호출할 수 있도록 함
window.initializeImageEditor = function() {
console.log('=== initializeImageEditor 함수 시작 ===');
console.log('Fabric.js 확인:', typeof fabric);
console.log('fabric 객체:', fabric);
if (typeof fabric === 'undefined') {
console.error('Fabric.js가 로드되지 않았습니다!');
return;
}
const openBtn = document.getElementById('openEditorBtn');
const targetImg = document.getElementById('targetImage');
const imageContainer = document.querySelector('.image-container');
// null 체크 추가 (view 모드에서는 openBtn이 없을 수 있음)
if (!imageContainer) {
console.warn('이미지 편집기 초기화 실패: imageContainer를 찾을 수 없습니다.');
return;
}
// view 모드가 아닌 경우에만 openBtn과 targetImg 체크
const mode = '<?= $mode ?>';
if (mode !== 'view') {
if (!openBtn || !targetImg) {
console.warn('이미지 편집기 초기화 실패: 필요한 DOM 요소를 찾을 수 없습니다.');
console.log('openBtn:', openBtn);
console.log('targetImg:', targetImg);
console.log('imageContainer:', imageContainer);
return;
}
} else {
console.log('view 모드: 이미지 편집 기능 비활성화, 붙여넣기만 활성화');
// view 모드에서는 붙여넣기 기능만 활성화
document.addEventListener('paste', handlePaste);
console.log('view 모드에서 전역 붙여넣기 이벤트 리스너 등록됨');
return;
}
// pasteOverlay는 선택적 요소로 처리
const pasteOverlay = document.querySelector('.paste-overlay');
// 붙여넣기 이벤트 처리 함수
function handlePaste(event) {
console.log('붙여넣기 이벤트 발생:', event);
console.log('clipboardData:', event.clipboardData);
const items = (event.clipboardData || event.originalEvent?.clipboardData)?.items;
console.log('clipboard items:', items);
if (!items) {
console.log('클립보드 데이터가 없습니다.');
return;
}
for (let item of items) {
console.log('클립보드 아이템:', item.type);
if (item.type.indexOf('image') !== -1) {
console.log('이미지 발견, 처리 중...');
const blob = item.getAsFile();
const reader = new FileReader();
reader.onload = function(e) {
console.log('이미지 로드 완료');
// view 모드가 아닌 경우에만 targetImg 업데이트
const mode = '<?= $mode ?>';
if (mode !== 'view') {
if (targetImg) {
targetImg.src = e.target.result;
console.log('이미지가 붙여넣기되었습니다:', e.target.result.substring(0, 50) + '...');
}
} else {
console.log('view 모드: 이미지 붙여넣기 완료 (표시만)');
}
// 붙여넣기 성공 피드백
if (pasteOverlay) {
showPasteFeedback(true);
}
};
reader.onerror = function(e) {
console.error('이미지 로드 실패:', e);
};
reader.readAsDataURL(blob);
event.preventDefault();
break;
}
}
}
// 붙여넣기 피드백 표시
function showPasteFeedback(success = false) {
if (!pasteOverlay) {
console.log('pasteOverlay 요소가 없습니다.');
return;
}
if (success) {
pasteOverlay.innerHTML = '<i class="bi bi-check-circle"></i><span>이미지가 붙여넣기되었습니다!</span>';
pasteOverlay.style.background = 'rgba(40, 167, 69, 0.8)';
} else {
pasteOverlay.innerHTML = '<i class="bi bi-clipboard-plus"></i><span>Ctrl+V로 이미지 붙여넣기</span>';
pasteOverlay.style.background = 'rgba(0, 123, 255, 0.8)';
}
pasteOverlay.style.display = 'block';
pasteOverlay.classList.add('show');
setTimeout(() => {
pasteOverlay.classList.remove('show');
setTimeout(() => {
pasteOverlay.style.display = 'none';
}, 300);
}, 2000);
}
// 기존 이벤트 리스너 제거 (중복 방지)
document.removeEventListener('paste', handlePaste);
imageContainer.removeEventListener('click', imageContainerClickHandler);
imageContainer.removeEventListener('focus', imageContainerFocusHandler);
imageContainer.removeEventListener('blur', imageContainerBlurHandler);
openBtn.removeEventListener('click', openBtnClickHandler);
// 이벤트 핸들러 함수들
function imageContainerClickHandler() {
imageContainer.focus();
}
function imageContainerFocusHandler() {
showPasteFeedback();
}
function imageContainerBlurHandler() {
pasteOverlay.classList.remove('show');
}
function openBtnClickHandler() {
console.log('그리기 버튼이 클릭되었습니다.');
console.log('openImageEditor 함수 타입:', typeof openImageEditor);
console.log('openImageEditor 함수:', openImageEditor);
let src = targetImg ? targetImg.src : '';
console.log('편집할 이미지 소스:', src);
// 이미지가 없거나 placeholder인 경우 빈 문자열로 설정
if (!src || src.includes('placeholder') || src === 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iI2Y5ZjlmOSIvPjwvc3ZnPg==') {
console.log('이미지가 없거나 placeholder, 새로운 빈 캔버스로 시작');
src = '';
}
if (typeof openImageEditor !== 'function') {
console.error('openImageEditor가 함수가 아닙니다!');
console.error('openImageEditor 값:', openImageEditor);
return;
}
console.log('openImageEditor 함수 호출 시도...');
try {
const result = openImageEditor(src);
console.log('openImageEditor 호출 결과:', result);
console.log('result 타입:', typeof result);
if (result && typeof result.then === 'function') {
console.log('Promise 반환됨, then 체인 시작...');
result.then(newUrl => {
// 편집된 이미지를 화면에 반영
console.log('편집 완료, 새로운 이미지 URL:', newUrl);
if (targetImg) {
targetImg.src = newUrl;
}
}).catch(err => {
// 사용자가 취소했을 때
console.log('편집 취소:', err.message);
console.error('편집 오류 상세:', err);
});
} else {
console.error('openImageEditor가 Promise를 반환하지 않습니다!');
}
} catch (error) {
console.error('openImageEditor 호출 중 오류:', error);
console.error('오류 스택:', error.stack);
}
}
// 그리기 관련 코드
// 붙여넣기 이벤트 리스너 추가 (전역 이벤트)
document.addEventListener('paste', handlePaste);
console.log('전역 붙여넣기 이벤트 리스너 등록됨');
// 이미지 컨테이너 클릭 시 포커스
imageContainer.addEventListener('click', imageContainerClickHandler);
// 이미지 컨테이너에 포커스 가능하도록 설정
imageContainer.tabIndex = 0;
imageContainer.style.cursor = 'pointer';
imageContainer.title = '클릭 후 Ctrl+V로 이미지 붙여넣기';
// 포커스 시 오버레이 표시
imageContainer.addEventListener('focus', imageContainerFocusHandler);
// 포커스 해제 시 오버레이 숨김
imageContainer.addEventListener('blur', imageContainerBlurHandler);
// 마우스 오버 시 힌트 표시
imageContainer.addEventListener('mouseenter', function() {
if (pasteOverlay) {
pasteOverlay.style.display = 'block';
showPasteFeedback(false);
}
});
imageContainer.addEventListener('mouseleave', function() {
if (pasteOverlay) {
setTimeout(() => {
pasteOverlay.style.display = 'none';
}, 1000);
}
});
// 그리기 버튼 클릭 이벤트 리스너 추가
openBtn.addEventListener('click', openBtnClickHandler);
console.log('이미지 편집기 초기화 완료');
console.log('그리기 버튼 이벤트 리스너 등록됨:', openBtn);
};
</script>
<script>
var ajaxRequest_write =null;
// 전역 변수로 문자입력 모드 관리
let textMode = false;
let isEraser = false; // 이름을 isEraser 로 통일
// 1) calculateSum 수정: 연신율계산 후(calcAfterList[]) 처리 추가
function calculateSum() {
const inputList = $('input[name="inputList[]"]');
const bendingList = $('input[name="bendingrateList[]"]');
const calcAfterList = $('input[name="calcAfterList[]"]');
const sumList = $('input[name="sumList[]"]');
let accumulated = 0;
inputList.each(function(index) {
const inp = parseFloat(inputList.eq(index).val()) || 0;
const bend = parseFloat(bendingList.eq(index).val()) || 0;
// ────────────────────────────────
// 변경: 입력값에서 빼기 대신, bend(±1)를 더합니다.
const diff = inp + bend;
// ────────────────────────────────
calcAfterList.eq(index).val(diff);
accumulated += diff;
sumList.eq(index).val(accumulated);
});
$('#widthsum').val(accumulated);
}
// 2) addInitialColumn 수정
function addInitialColumn() {
const tableBody = $('#tableBody');
if (!tableBody.length) return;
// rowsData 배열에서 span의 className에서 'input-container'를 제거
const rowsData = [
{ label: '번호', type: 'span', className: 'form-control text-center' },
{ label: '입력', type: 'input', className: 'form-control yellowBold text-center', name: 'inputList[]', event: calculateSum },
{ label: '연신율', type: 'input', className: 'form-control text-center', name: 'bendingrateList[]', event: calculateSum },
{ label: '연신율계산 후', type: 'input', className: 'form-control text-center', name: 'calcAfterList[]', event: null, readonly: true },
{ label: '합계', type: 'input', className: 'form-control orangeBlackBold text-center', name: 'sumList[]', event: null },
{ label: '음영', type: 'checkbox', className: 'form-check-input', name: 'colorList[]' },
{ label: 'A각 표시', type: 'checkbox', className: 'form-check-input', name: 'AList[]' }
];
tableBody.empty();
rowsData.forEach((rowData, rowIndex) => {
const $row = $('<tr>');
// 첫 번째 셀: 라벨
$row.append($('<td>').addClass('lightgray').text(rowData.label));
// 두 번째 셀: 모든 행에 input-container 적용
const $cell = $('<td>').addClass('input-container');
if (rowData.type === 'span') {
// 번호용 span: 모든 요소와 동일한 폭 적용
$cell.append(
$('<span>')
.addClass(rowData.className)
.css({ display: 'inline-block', width: '40px', height: '24px', 'text-align': 'center', 'line-height': '24px' })
.text(rowIndex + 1)
);
} else {
// 모든 input 요소: 동일한 폭과 높이 적용
const $input = $('<input>')
.attr('type', rowData.type === 'checkbox' ? 'checkbox' : 'text')
.addClass(rowData.className)
.css(rowData.type === 'checkbox' ? { width: '16px', height: '16px' } : { width: '40px', height: '24px' })
.attr('name', rowData.name)
.prop('readonly', !!rowData.readonly)
.on(rowData.event ? 'input change' : [], rowData.event || (() => {}))
.attr('autocomplete', 'off');
$cell.append($input);
}
$row.append($cell);
tableBody.append($row);
wrapColumnsAndAttachRemove();
});
}
// 3) addColumn 수정: 새로 생긴 "연신율계산 후" 행에도 input 추가
function addColumn() {
const tableBody = $('#tableBody');
let $rows = tableBody.find('tr');
if ($rows.length === 0) {
addInitialColumn();
$rows = tableBody.find('tr');
}
// 새 칸 번호
const newIndex = $rows.first().find('.input-container span').length + 1;
$rows.each(function(rowIdx) {
const $cell = $(this).find('.input-container');
if (rowIdx === 0) {
// 번호 행: 동일한 폭 적용
$cell.append(
$('<span>')
.addClass('form-control text-center viewNoBtn')
.css({ width: '40px', height: '24px', 'text-align': 'center', 'line-height': '24px' })
.text(newIndex)
);
} else {
let $input = $('<input>')
.addClass('form-control')
.attr('autocomplete', 'off');
switch (rowIdx) {
case 1: // 입력
$input
.attr('type', 'text')
.addClass('yellowBold text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'inputList[]')
.on('input change', calculateSum);
break;
case 2: // 연신율
$input
.attr('type', 'text')
.addClass('text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'bendingrateList[]')
.on('input change', calculateSum);
break;
case 3: // 연신율계산 후
$input
.attr('type', 'text')
.addClass('text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'calcAfterList[]')
.prop('readonly', true);
break;
case 4: // 합계
$input
.attr('type', 'text')
.addClass('orangeBlackBold text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'sumList[]');
break;
case 5: // 음영
$input
.attr('type', 'checkbox')
.addClass('form-check-input')
.css({ width: '16px', height: '16px' })
.attr('name', 'colorList[]');
break;
case 6: // A각 표시
$input
.attr('type', 'checkbox')
.addClass('form-check-input')
.css({ width: '16px', height: '16px' })
.attr('name', 'AList[]');
break;
}
$cell.append($input);
}
wrapColumnsAndAttachRemove();
});
}
// 특정 위치에 열 삽입하는 함수
function insertColumnAt(index) {
const tableBody = $('#tableBody');
let $rows = tableBody.find('tr');
if ($rows.length === 0) {
addInitialColumn();
$rows = tableBody.find('tr');
}
$rows.each(function(rowIdx) {
const $cell = $(this).find('.input-container');
const $colCells = $cell.find('.col-cell');
if (rowIdx === 0) {
// 번호 행: span 요소 삽입
const $newSpan = $('<span>')
.addClass('form-control text-center viewNoBtn')
.css({ width: '40px', height: '24px', 'text-align': 'center', 'line-height': '24px' })
.text(index + 1);
// 해당 위치에 삽입
if (index < $colCells.length) {
$colCells.eq(index).before($('<div class="col-cell"></div>').append($newSpan));
} else {
$cell.append($('<div class="col-cell"></div>').append($newSpan));
}
} else {
let $input = $('<input>')
.addClass('form-control')
.attr('autocomplete', 'off');
switch (rowIdx) {
case 1: // 입력
$input
.attr('type', 'text')
.addClass('yellowBold text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'inputList[]')
.on('input change', calculateSum);
break;
case 2: // 연신율
$input
.attr('type', 'text')
.addClass('text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'bendingrateList[]')
.on('input change', calculateSum);
break;
case 3: // 연신율계산 후
$input
.attr('type', 'text')
.addClass('text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'calcAfterList[]')
.prop('readonly', true);
break;
case 4: // 합계
$input
.attr('type', 'text')
.addClass('orangeBlackBold text-center')
.css({ width: '40px', height: '24px' })
.attr('name', 'sumList[]');
break;
case 5: // 음영
$input
.attr('type', 'checkbox')
.addClass('form-check-input')
.css({ width: '16px', height: '16px' })
.attr('name', 'colorList[]');
break;
case 6: // A각 표시
$input
.attr('type', 'checkbox')
.addClass('form-check-input')
.css({ width: '16px', height: '16px' })
.attr('name', 'AList[]');
break;
}
// 해당 위치에 삽입
if (index < $colCells.length) {
$colCells.eq(index).before($('<div class="col-cell"></div>').append($input));
} else {
$cell.append($('<div class="col-cell"></div>').append($input));
}
}
});
// 새로 추가된 열에 버튼들 추가
addButtonsToNewColumns();
// 번호 다시 매기기
$('#tableBody tr:first .col-cell span').each(function(i) {
$(this).text(i + 1);
});
// 합계 재계산
calculateSum();
alertToast('앞쪽에 열추가');
}
// 새로 추가된 열에 버튼들을 추가하는 함수
function addButtonsToNewColumns() {
$('#tableBody tr:first .col-cell').each(function(idx) {
const $colCell = $(this);
// 추가 버튼이 없으면 추가
if (!$colCell.find('.add-col').length) {
$colCell.append('<button type="button" class="add-col">+</button>');
}
// 삭제 버튼이 없으면 추가
if (!$colCell.find('.remove-col').length) {
$colCell.append('<button type="button" class="remove-col"></button>');
}
});
}
function emptyColumn() {
const tableBody = $('#tableBody');
tableBody.find('input').each(function() {
const inputType = $(this).attr('type');
if (inputType === 'checkbox') {
$(this).prop('checked', false); // 체크박스 해제
} else {
$(this).val(''); // 텍스트 필드 비우기
}
});
}
function populateTableWithData() {
const inputList = <?php echo json_encode($inputList ?? []); ?>;
const bendingrateList = <?php echo json_encode($bendingrateList ?? []); ?>;
const sumList = <?php echo json_encode($sumList ?? []); ?>;
const colorList = <?php echo json_encode($colorList ?? []); ?>;
const AList = <?php echo json_encode($AList ?? []); ?>;
const tableBody = $('#tableBody');
if (!tableBody.length) return;
inputList.forEach(function (input, index) {
if (index === 0) {
addInitialColumn(); // 첫 번째 열은 기본 열 추가
} else {
addColumn(); // 이후 열 추가
}
});
// 데이터 채우기
inputList.forEach(function (input, index) {
// 입력 추가
tableBody.find('tr:nth-child(2) .input-container input').eq(index).val(input);
// 연신율 추가
tableBody.find('tr:nth-child(3) .input-container input').eq(index).val(bendingrateList[index] || '');
// 합계 추가
tableBody.find('tr:nth-child(5) .input-container input').eq(index).val(sumList[index] || '');
// 음영 체크박스 추가
tableBody.find('tr:nth-child(6) .input-container input').eq(index).prop('checked', colorList[index] || false);
// A각 표시 체크박스 추가
tableBody.find('tr:nth-child(7) .input-container input').eq(index).prop('checked', AList[index] || false);
});
}
function removeColumn() {
const tableBody = $('#tableBody');
const rows = tableBody.find('tr');
if (rows.length === 0) return;
rows.each(function (i) {
const inputContainer = $(this).find('.input-container');
if (i === 0) {
// 첫 번째 행(번호 행)은 span 요소를 제거합니다.
const spans = inputContainer.find('span');
if (spans.length > 1) {
inputContainer.find('span').last().remove();
}
} else {
// 나머지 행은 input 요소를 제거합니다.
const inputs = inputContainer.find('input');
if (inputs.length > 1) {
inputContainer.find('input').last().remove();
}
}
});
}
$(document).ready(function () {
const mode = '<?php echo $mode; ?>';
$("#copyBtn").click(function(){
location.href = 'write_form.php?mode=copy&num=' + $("#num").val() + "&tablename=" + $("#tablename").val() ;
}); // end of function
if (mode === 'view' || mode === 'modify' || mode === 'copy' || mode === 'write' ) {
populateTableWithData();
} else {
addInitialColumn(); // 새로 입력하는 경우 기본 열 추가
}
if (mode === 'view') {
disableInputsForViewMode();
}
else
{ // view가 아닐때만
$('#emptyColumnBtn').on('click', emptyColumn);
$('#addColumnBtn').on('click', addColumn);
$('#removeColumnBtn').on('click', removeColumn);
}
var loader = $('#loadingOverlay');
if (loader.length) {
loader.hide();
}
});
function disableInputsForViewMode() {
$('input, textarea').prop('readonly', true);
$('select').prop('disabled', true);
$('input[type=file]').prop('readonly', false);
$('input[type=checkbox]').prop('disabled', true);
$('.viewNoBtn').prop('disabled', true); // 뷰모드에서는 금지
$('input[type=radio]').prop('disabled', true);
}
$(document).ready(function() {
// Log 파일보기
$("#showlogBtn").click( function() {
var num = '<?php echo $num; ?>'
// table 이름을 넣어야 함
var workitem = 'bending' ;
// 버튼 비활성화
var btn = $(this);
popupCenter("../Showlog.php?num=" + num + "&workitem=" + workitem , '로그기록', 500, 500);
btn.prop('disabled', false);
});
// 저장 버튼 클릭 이벤트
$('#saveBtn').off('click').on('click', function() {
// 이미지 편집이 완료되었지만 저장되지 않은 상태인지 확인
const targetImage = document.getElementById('targetImage');
const hasUnsavedImage = targetImage && targetImage.src && targetImage.src.startsWith('data:');
if (hasUnsavedImage) {
Swal.fire({
title: '이미지 편집 저장 확인',
text: '편집된 이미지가 저장되지 않았습니다. 저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#6c757d',
confirmButtonText: '네, 저장하겠습니다',
cancelButtonText: '아니오, 그대로 저장'
}).then((result) => {
if (result.isConfirmed) {
// 이미지 저장 후 파일 저장
saveEditedImageAndFile();
} else {
// 이미지 저장 없이 파일 저장
saveFileOnly();
}
});
} else {
// 이미지 편집이 없으면 바로 파일 저장
saveFileOnly();
}
});
// 편집된 이미지 저장 후 파일 저장하는 함수
async function saveEditedImageAndFile() {
const targetImage = document.getElementById('targetImage');
if (targetImage && targetImage.src && targetImage.src.startsWith('data:')) {
try {
// 이미지 저장
await saveEditedImage(targetImage.src);
// 파일 저장 진행
saveFileOnly();
} catch (error) {
console.error('이미지 저장 실패:', error);
// 이미지 저장 실패해도 파일 저장은 진행
saveFileOnly();
}
} else {
// 저장할 이미지가 없으면 바로 파일 저장
saveFileOnly();
}
}
// 파일만 저장하는 함수
function saveFileOnly() {
const formData = new FormData($('#board_form')[0]);
// JSON 데이터 생성
const inputList = [];
$('input[name="inputList[]"]').each(function() {
inputList.push($(this).val());
});
const bendingrateList = [];
$('input[name="bendingrateList[]"]').each(function() {
bendingrateList.push($(this).val());
});
const sumList = [];
$('input[name="sumList[]"]').each(function() {
sumList.push($(this).val());
});
const colorList = [];
$('input[name="colorList[]"]').each(function() {
colorList.push($(this).is(':checked'));
});
const AList = [];
$('input[name="AList[]"]').each(function() {
AList.push($(this).is(':checked'));
});
const calcAfterList = [];
$('input[name="calcAfterList[]"]').each(function() {
calcAfterList.push($(this).val());
});
// JSON 데이터를 hidden input에 설정
formData.append('inputList', JSON.stringify(inputList));
formData.append('bendingrateList', JSON.stringify(bendingrateList));
formData.append('sumList', JSON.stringify(sumList));
formData.append('colorList', JSON.stringify(colorList));
formData.append('AList', JSON.stringify(AList));
formData.append('calcAfterList', JSON.stringify(calcAfterList));
// AJAX로 저장
$.ajax({
url: 'insert.php',
type: 'POST',
data: formData,
processData: false,
contentType: false,
dataType: 'json',
success: function(response) {
console.log(' saveBtn 실행 저장 응답:', response);
try {
// 응답이 문자열인 경우 JSON 파싱 시도
let result;
if (typeof response === 'string') {
result = JSON.parse(response);
} else {
result = response;
}
if (result && result.success) {
Swal.fire({
title: '저장 완료',
text: '데이터가 성공적으로 저장되었습니다.',
icon: 'success',
confirmButtonText: '확인'
}).then((result) => {
// 저장 성공 시 페이지 새로고침 또는 다른 처리
if (result.num) {
location.href = 'write_form.php?mode=view&num=' + result.num + '&tablename=' + $('#tablename').val();
} else {
// num이 없으면 현재 페이지 새로고침
// location.reload();
}
});
} else {
Swal.fire({
title: '저장 실패',
text: '저장 중 오류가 발생했습니다: ' + (result ? result.message : '알 수 없는 오류'),
icon: 'error',
confirmButtonText: '확인'
});
}
} catch (e) {
console.error('저장 응답 파싱 오류:', e);
console.error('응답 내용:', response);
// JSON 파싱 실패해도 성공으로 처리 (insert.php가 성공 시 다른 형식 반환할 수 있음)
Swal.fire({
title: '저장 완료',
text: '데이터가 성공적으로 저장되었습니다.',
icon: 'success',
confirmButtonText: '확인'
}).then(() => {
location.reload();
});
}
},
error: function(xhr, status, error) {
Swal.fire({
title: '저장 오류',
text: '저장 중 오류가 발생했습니다.',
icon: 'error',
confirmButtonText: '확인'
});
console.error('저장 오류:', error);
}
});
}
// saveEditedImage 함수 (모듈 스크립트에서 정의된 함수 사용)
async function saveEditedImage(imageData) {
try {
console.log('이미지 저장 시작:', imageData.substring(0, 50) + '...');
// data URL을 Blob으로 변환
const response = await fetch(imageData);
const blob = await response.blob();
// FormData 구성
const formData = new FormData();
formData.append('upfile', blob, 'edited_image.png');
formData.append('num', '<?= $num ?>');
formData.append('mode', '<?= $mode ?>');
// 추가 데이터 (bending 테이블 관련)
formData.append('item_sep', '<?= $row['item_sep'] ?? '' ?>');
formData.append('model_UA', '<?= $row['model_UA'] ?? '' ?>');
formData.append('item_bending', '<?= $row['item_bending'] ?? '' ?>');
formData.append('itemName', '<?= $row['itemName'] ?? '' ?>');
formData.append('item_spec', '<?= $row['item_spec'] ?? '' ?>');
console.log('FormData 구성 완료, 서버 전송 중...');
const saveResponse = await fetch('save_edited_image.php', {
method: 'POST',
body: formData
});
if (!saveResponse.ok) {
throw new Error('서버 저장 실패');
}
const result = await saveResponse.json();
if (result.success) {
console.log('이미지 저장 성공:', result);
// 성공 메시지 표시
if (typeof Toastify !== 'undefined') {
Toastify({
text: "이미지 저장 완료",
duration: 2000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#28a745",
}).showToast();
} else {
alert('이미지가 성공적으로 저장되었습니다.');
}
} else {
console.error('이미지 저장 실패:', result.message);
if (typeof Toastify !== 'undefined') {
Toastify({
text: "이미지 저장 실패: " + result.message,
duration: 3000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#dc3545",
}).showToast();
} else {
alert('이미지 저장 실패: ' + result.message);
}
}
} catch (error) {
console.error('이미지 저장 오류:', error);
if (typeof Toastify !== 'undefined') {
Toastify({
text: "이미지 저장 중 오류 발생",
duration: 3000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#dc3545",
}).showToast();
} else {
alert('이미지 저장 중 오류가 발생했습니다.');
}
}
}
});
// 테이블을 다시 그린 직후, 또는 addColumn/addInitialColumn 끝에 호출하세요.
function wrapColumnsAndAttachRemove() {
$('#tableBody tr').each(function(rowIdx) {
const $cell = $(this).find('td.input-container');
// 이미 wrap 되어 있지 않은 직접 자식(input, span 등)만 골라서 감싸기
$cell
.contents()
.filter(function() {
return this.nodeType === 1 && !$(this).closest('.col-cell').length;
})
.each(function() {
$(this).wrap('<div class="col-cell"></div>');
});
});
// 모든 열에 추가/삭제 버튼 붙이기
addButtonsToNewColumns();
}
// 열추가동작
$(document).on('click', '.add-col', function() {
const $wrapper = $(this).closest('.col-cell');
const idx = $wrapper.index(); // 몇 번째 열인지
// mode가 view가 아닐때 해당 열(인덱스) 위치에 새 열 삽입
if ($('#mode').val() !== 'view') {
insertColumnAt(idx);
}
});
// 열삭제동작
$(document).on('click', '.remove-col', function() {
const $wrapper = $(this).closest('.col-cell');
const idx = $wrapper.index(); // 몇 번째 열인지
// mode가 view가 아닐때 해당 열(인덱스) 전체를 지움
if ($('#mode').val() !== 'view') {
$('#tableBody .input-container').each(function() {
$(this).find('.col-cell').eq(idx).remove();
});
// 번호 다시 매기기
$('#tableBody tr:first .col-cell span').each(function(i) {
$(this).text(i + 1);
});
// 합계 재계산
calculateSum();
alertToast('해당열 열삭제');
}
});
</script>
<script>
// 이미지 편집 관련 전역 변수 선언
$(document).ready(function() {
// DOM 요소 확인 및 이벤트 리스너 등록
setTimeout(() => {
const openBtn = document.getElementById('openEditorBtn');
const targetImg = document.getElementById('targetImage');
const imageContainer = document.querySelector('.image-container');
const pasteOverlay = document.querySelector('.paste-overlay');
console.log('DOM 요소 확인:', {
openBtn: !!openBtn,
targetImg: !!targetImg,
imageContainer: !!imageContainer,
pasteOverlay: !!pasteOverlay
});
if (openBtn) {
console.log('그리기 버튼 찾음:', openBtn);
console.log('그리기 버튼 텍스트:', openBtn.textContent);
console.log('그리기 버튼 클래스:', openBtn.className);
console.log('그리기 버튼 스타일:', openBtn.style.display);
// 그리기 버튼에 직접 이벤트 리스너 추가
openBtn.onclick = function() {
console.log('그리기 버튼 클릭됨 (직접 이벤트)');
const globalOpenImageEditor = window.openImageEditor;
console.log('전역 openImageEditor 확인:', typeof globalOpenImageEditor);
if (typeof globalOpenImageEditor !== 'function') {
console.error('전역 openImageEditor가 함수가 아닙니다!');
return;
}
// 현재 이미지 요소 찾기 (기존 targetImg 또는 새로 생성된 이미지)
let currentImg = targetImg || imageContainer.querySelector('#targetImage');
let src = currentImg ? currentImg.src : '';
console.log('편집할 이미지 소스:', src);
// 이미지가 없거나 placeholder인 경우 빈 문자열로 설정
if (!src || src.includes('placeholder') || src === 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iI2Y5ZjlmOSIvPjwvc3ZnPg==') {
console.log('이미지가 없거나 placeholder, 새로운 빈 캔버스로 시작');
src = '';
}
try {
const result = globalOpenImageEditor(src);
console.log('openImageEditor 호출 결과:', result);
if (result && typeof result.then === 'function') {
result.then(newUrl => {
console.log('편집 완료, 새로운 이미지 URL:', newUrl);
// 현재 이미지 요소 찾기 (기존 targetImg 또는 새로 생성된 이미지)
let imgElement = targetImg || imageContainer.querySelector('#targetImage');
if (!imgElement) {
console.log('이미지 요소가 없어서 새로 생성');
imgElement = document.createElement('img');
imgElement.id = 'targetImage';
imgElement.className = 'img-fluid';
imgElement.style.maxWidth = '100%';
imgElement.style.height = 'auto';
imageContainer.appendChild(imgElement);
}
imgElement.src = newUrl;
// "이미지가 없습니다" 메시지 숨기기
const noImageMsg = imageContainer.querySelector('p.text-muted');
if (noImageMsg && noImageMsg.textContent.includes('이미지가 없습니다')) {
noImageMsg.style.display = 'none';
console.log('"이미지가 없습니다" 메시지 숨김');
}
}).catch(err => {
console.log('편집 취소:', err.message);
});
}
} catch (error) {
console.error('openImageEditor 호출 중 오류:', error);
}
};
console.log('그리기 버튼 이벤트 리스너 등록 완료');
} else {
console.warn('그리기 버튼을 찾을 수 없습니다!');
}
if (targetImg) console.log('타겟 이미지 찾음:', targetImg.src);
if (imageContainer) console.log('이미지 컨테이너 찾음');
if (pasteOverlay) console.log('붙여넣기 오버레이 찾음');
// 붙여넣기 기능 초기화 (imageContainer만 있으면 동작)
if (imageContainer) {
console.log('붙여넣기 기능 초기화 시작...');
// 붙여넣기 이벤트 처리 함수
function handlePaste(event) {
const items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (let item of items) {
if (item.type.indexOf('image') !== -1) {
const blob = item.getAsFile();
const reader = new FileReader();
reader.onload = function(e) {
// targetImg가 있으면 업데이트, 없으면 새로 생성
let imgElement = targetImg;
if (!imgElement) {
console.log('targetImg가 없어서 새로 생성');
imgElement = document.createElement('img');
imgElement.id = 'targetImage';
imgElement.className = 'img-fluid';
imgElement.style.maxWidth = '100%';
imgElement.style.height = 'auto';
imageContainer.appendChild(imgElement);
}
imgElement.src = e.target.result;
console.log('이미지가 붙여넣기되었습니다:', e.target.result);
// "이미지가 없습니다" 메시지 숨기기
const noImageMsg = imageContainer.querySelector('p.text-muted');
if (noImageMsg && noImageMsg.textContent.includes('이미지가 없습니다')) {
noImageMsg.style.display = 'none';
console.log('"이미지가 없습니다" 메시지 숨김');
}
// 붙여넣기 성공 피드백
showPasteFeedback(true);
};
reader.readAsDataURL(blob);
event.preventDefault();
break;
}
}
}
// 붙여넣기 피드백 표시
function showPasteFeedback(success = false) {
if (pasteOverlay) {
if (success) {
pasteOverlay.innerHTML = '<i class="bi bi-check-circle"></i><span>이미지가 붙여넣기되었습니다!</span>';
pasteOverlay.style.background = 'rgba(40, 167, 69, 0.8)';
} else {
pasteOverlay.innerHTML = '<i class="bi bi-clipboard-plus"></i><span>Ctrl+V로 이미지 붙여넣기</span>';
pasteOverlay.style.background = 'rgba(0, 123, 255, 0.8)';
}
pasteOverlay.classList.add('show');
setTimeout(() => {
pasteOverlay.classList.remove('show');
}, 2000);
} else {
// pasteOverlay가 없으면 간단한 콘솔 메시지
if (success) {
console.log('이미지가 성공적으로 붙여넣기되었습니다!');
}
}
}
// 이벤트 핸들러 함수들
function imageContainerClickHandler() {
imageContainer.focus();
}
function imageContainerFocusHandler() {
showPasteFeedback();
}
function imageContainerBlurHandler() {
if (pasteOverlay) {
pasteOverlay.classList.remove('show');
}
}
// 기존 이벤트 리스너 제거 (중복 방지)
document.removeEventListener('paste', handlePaste);
imageContainer.removeEventListener('click', imageContainerClickHandler);
if (pasteOverlay) {
imageContainer.removeEventListener('focus', imageContainerFocusHandler);
imageContainer.removeEventListener('blur', imageContainerBlurHandler);
}
// 붙여넣기 이벤트 리스너 추가
document.addEventListener('paste', handlePaste);
// 이미지 컨테이너 클릭 시 포커스
imageContainer.addEventListener('click', imageContainerClickHandler);
// 이미지 컨테이너에 포커스 가능하도록 설정
imageContainer.tabIndex = 0;
imageContainer.title = '클릭 후 Ctrl+V로 이미지 붙여넣기';
// 포커스 시 오버레이 표시 (pasteOverlay가 있을 때만)
if (pasteOverlay) {
imageContainer.addEventListener('focus', imageContainerFocusHandler);
imageContainer.addEventListener('blur', imageContainerBlurHandler);
}
console.log('붙여넣기 기능 초기화 완료');
} else {
console.warn('붙여넣기 기능 초기화 실패: 필요한 DOM 요소를 찾을 수 없습니다.');
}
}, 100);
});
</script>
</body>
</html>