v4:코드모듈화_20260123
This commit is contained in:
@@ -1074,6 +1074,8 @@
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/css/editor.css">
|
||||
<script src="/static/js/editor.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- 상단 툴바 -->
|
||||
@@ -1217,17 +1219,7 @@
|
||||
|
||||
<!-- 가운데 뷰어 -->
|
||||
<div class="main">
|
||||
<!-- 서식 바 (편집 모드) -->
|
||||
<div class="format-bar" id="formatBar">
|
||||
<button class="format-btn" onclick="formatText('bold')"><b>B</b></button>
|
||||
<button class="format-btn" onclick="formatText('italic')"><i>I</i></button>
|
||||
<button class="format-btn" onclick="formatText('underline')"><u>U</u></button>
|
||||
<div class="format-divider"></div>
|
||||
<button class="format-btn" onclick="formatText('justifyLeft')">⫷</button>
|
||||
<button class="format-btn" onclick="formatText('justifyCenter')">☰</button>
|
||||
<button class="format-btn" onclick="formatText('justifyRight')">⫸</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="viewer" id="viewer">
|
||||
<div class="a4-wrapper" id="a4Wrapper">
|
||||
<div class="a4-preview" id="a4Preview">
|
||||
@@ -1531,7 +1523,8 @@
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
html: html,
|
||||
doc_type: currentDocType
|
||||
doc_type: currentDocType,
|
||||
style_grouping: true
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1628,7 +1621,8 @@
|
||||
body: JSON.stringify({
|
||||
current_html: generatedHTML,
|
||||
selected_text: selectedText,
|
||||
request: request
|
||||
request: request,
|
||||
doc_type: currentDocType // ← 추가
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1696,10 +1690,38 @@
|
||||
if (targetEl.nodeType === 3) {
|
||||
targetEl = targetEl.parentElement;
|
||||
}
|
||||
// 적절한 부모 찾기 (div, section 등)
|
||||
const parent = targetEl.closest('.lead-box, .section, .info-table, .data-table, .process-flow') || targetEl.closest('div');
|
||||
if (parent) {
|
||||
parent.outerHTML = modifiedContent;
|
||||
|
||||
if (currentDocType === 'report') {
|
||||
// ===== 보고서: 안전한 부모만 교체 =====
|
||||
// sheet, body-content 등 페이지 구조는 절대 건드리지 않음
|
||||
const dangerousClasses = ['sheet', 'body-content', 'page-header', 'page-footer', 'a4-preview'];
|
||||
|
||||
// p, li, td, h1~h6 등 안전한 요소 찾기
|
||||
const safeParent = targetEl.closest('p, li, td, th, h1, h2, h3, h4, h5, h6, ul, ol, table, figure');
|
||||
|
||||
if (safeParent && !dangerousClasses.some(cls => safeParent.classList.contains(cls))) {
|
||||
// 선택된 요소 뒤에 새 구조 삽입
|
||||
safeParent.insertAdjacentHTML('afterend', modifiedContent);
|
||||
// 기존 요소는 유지하거나 숨김 처리
|
||||
// safeParent.style.display = 'none'; // 선택: 기존 숨기기
|
||||
safeParent.remove(); // 또는 삭제
|
||||
console.log('보고서 - 안전한 구조 교체:', safeParent.tagName);
|
||||
} else {
|
||||
// 안전한 부모를 못 찾으면 텍스트 앞에 구조 삽입
|
||||
console.log('보고서 - 안전한 부모 없음, 선택 위치에 삽입');
|
||||
const range = selectedRange.cloneRange();
|
||||
range.deleteContents();
|
||||
const temp = document.createElement('div');
|
||||
temp.innerHTML = modifiedContent;
|
||||
range.insertNode(temp.firstElementChild || temp);
|
||||
}
|
||||
|
||||
} else {
|
||||
// ===== 기획서: 기존 로직 =====
|
||||
const parent = targetEl.closest('.lead-box, .section, .info-table, .data-table, .process-flow') || targetEl.closest('div');
|
||||
if (parent) {
|
||||
parent.outerHTML = modifiedContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2196,6 +2218,93 @@
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
// ===== HWP 다운로드 (스타일 그루핑) =====
|
||||
async function downloadHwpStyled() {
|
||||
if (!generatedHTML) {
|
||||
alert('먼저 문서를 생성해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 편집된 내용 가져오기
|
||||
const frame = document.getElementById('previewFrame');
|
||||
const html = frame.contentDocument ?
|
||||
'<!DOCTYPE html>' + frame.contentDocument.documentElement.outerHTML :
|
||||
generatedHTML;
|
||||
|
||||
try {
|
||||
setStatus('HWP 변환 중...', true);
|
||||
|
||||
const response = await fetch('/export-hwp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
html: html,
|
||||
doc_type: currentDocType || 'report',
|
||||
style_grouping: true // ★ 스타일 그루핑 활성화
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const err = await response.json();
|
||||
throw new Error(err.error || 'HWP 변환 실패');
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `report_${new Date().toISOString().slice(0,10)}.hwp`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
setStatus('HWP 저장 완료', true);
|
||||
|
||||
} catch (error) {
|
||||
alert('HWP 변환 오류: ' + error.message);
|
||||
setStatus('오류 발생', false);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 스타일 분석 미리보기 (선택사항) =====
|
||||
async function analyzeStyles() {
|
||||
if (!generatedHTML) {
|
||||
alert('먼저 문서를 생성해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const frame = document.getElementById('previewFrame');
|
||||
const html = frame.contentDocument ?
|
||||
'<!DOCTYPE html>' + frame.contentDocument.documentElement.outerHTML :
|
||||
generatedHTML;
|
||||
|
||||
try {
|
||||
const response = await fetch('/analyze-styles', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ html: html })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
// 결과 표시
|
||||
let summary = `📊 스타일 분석 결과\n\n총 ${data.total_elements}개 요소\n\n`;
|
||||
summary += Object.entries(data.summary)
|
||||
.map(([k, v]) => `${k}: ${v}개`)
|
||||
.join('\n');
|
||||
|
||||
alert(summary);
|
||||
console.log('스타일 분석 상세:', data);
|
||||
|
||||
} catch (error) {
|
||||
alert('분석 오류: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function printDoc() {
|
||||
const frame = document.getElementById('previewFrame');
|
||||
if (frame.contentWindow) {
|
||||
|
||||
Reference in New Issue
Block a user