feat(est-test): 셀복사·셀붙여넣기
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -487,6 +487,8 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD
|
||||
- 남음: 구성비·요율 전환(CalcBase), 약어 표시(SName), 제비율 기준 문서 보기(원본 한글 파일).
|
||||
- [x] 수량산출서 검색·전체보기(원본 TFRMMULLANG btnSerch·btnAllDisplay — 빈칸·|·괄호 무시 포함 검색) — 고르기 줄을 `native-quantity-sheets.js` 로 옮겨 700줄 제한 유지.
|
||||
- 검증완료: `test_est_quantity_sheets.py` 검색 시험 포함 수량 시험 22개 통과. ORCA 브라우저에서 「집수」 검색 → 항목에 집수정이 있는 「배수」만·선택 이동, 전체보기 → 3개 복귀, 샘플 복구.
|
||||
- [x] 셀복사·셀붙여넣기(원본 ActionCellCopy·ActionCellPaste) — 마지막으로 누른 칸의 열을 고른 행들(없으면 그 행)만큼 복사(시스템 클립보드에도 글자로), 다른 칸을 누르고 붙이면 그 행부터 아래로 차례로 넣음(열 달라도 됨, 수치 칸은 수치만, 코드·결과비목 칸 거부).
|
||||
- 검증완료: 바인딩 시험 통과. ORCA 브라우저에서 자재 품명 2칸 복사 → 6번째 행 규격부터 붙여넣기(경유·휘발유), 코드 칸 거부, 샘플 복구.
|
||||
- [x] 산출 줄 잘라내기·복사·붙여넣기(원본 TFRMMULWORD popCut·popCopy·popPaste) — 산출 줄마다 복사·잘라내기·아래 붙여넣기. 붙일 때 수량 지정 표지를 떼고 글만(같은 항목이 두 번 잡히지 않게), 수량 지정된 줄은 잘라내기 거부.
|
||||
- 검증완료: 산출서·수량 흐름·바인딩 시험 22개 통과. ORCA 브라우저에서 표지 있는 줄 복사 → 아래 붙여넣기(표지 없음), 표지 줄 잘라내기 거부, 샘플 복구.
|
||||
- [x] 수량산출서 엑셀형식 전환(원본 TFRMMULLANG popSetMode — DataKind 로 편집기 교체) — 산출서 화면 「엑셀형식으로」: 엑셀 시트가 없으면 빈 시트를 만들어 엑셀형으로, 「일반형식으로」는 엑셀 내용을 보관한 채 끄고 셀 연결 수량을 쓰지 않음. 바꾼 산출서는 ESTX 저장 거부(JSON).
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
<script defer src="native-docs.js"></script>
|
||||
<script defer src="native-doc-forms.js"></script>
|
||||
<script defer src="native-block-file.js"></script>
|
||||
<script defer src="native-cell-clip.js"></script>
|
||||
<script defer src="native-wonga-tools.js"></script>
|
||||
<script defer src="native-estimate-print.js"></script>
|
||||
<script defer src="native-xml-check.js"></script>
|
||||
@@ -135,7 +136,9 @@
|
||||
><button data-action="select-all-rows">전체 선택</button
|
||||
><button data-action="block-del">블럭 삭제</button
|
||||
><button data-action="block-save-file">블럭 파일로 저장하기</button
|
||||
><button data-action="block-load-file">블럭 파일에서 붙여넣기</button>
|
||||
><button data-action="block-load-file">블럭 파일에서 붙여넣기</button
|
||||
><button data-action="cell-copy">셀복사</button
|
||||
><button data-action="cell-paste">셀붙여넣기</button>
|
||||
<hr />
|
||||
<button data-action="find">찾기·다음찾기(Ctrl+F)</button>
|
||||
<button data-action="multi-search">통합 검색(저장된 다른 작업)</button>
|
||||
|
||||
@@ -630,7 +630,8 @@ const EstBusinessActions = (() => {
|
||||
(typeof EstDocEditor !== "undefined" && EstDocEditor.handle(name, state, node)) ||
|
||||
(typeof EstDocForms !== "undefined" && EstDocForms.handle(name, state, node)) ||
|
||||
(typeof EstBlockFile !== "undefined" && EstBlockFile.handle(name, state)) ||
|
||||
(typeof EstDisplay !== "undefined" && EstDisplay.handle(name, state))
|
||||
(typeof EstDisplay !== "undefined" && EstDisplay.handle(name, state)) ||
|
||||
(typeof EstCellClip !== "undefined" && EstCellClip.handle(name, state))
|
||||
) {
|
||||
EstApp.render();
|
||||
} else if (name === "insert-annual") {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// 원본 셀복사·셀붙여넣기(TfrmEstMain ActionCellCopy·ActionCellPaste) — 마지막으로 누른 칸의 열을, 고른 행들(없으면 그 행)만큼 복사하고
|
||||
// 다른 칸을 누른 뒤 그 행부터 아래로 차례로 붙여넣는다(열이 달라도 됨). 코드·결과비목 칸은 연결 처리가 따로 있어 붙여넣기 거부.
|
||||
const EstCellClip = (() => {
|
||||
let last = null;
|
||||
function copy(state) {
|
||||
if (!last) throw Error("복사할 칸을 먼저 누르세요.");
|
||||
const rows = state.project.tables[last.table] || [],
|
||||
picked = [...state.selection].filter((i) => rows[i]).sort((a, b) => a - b),
|
||||
list = picked.includes(last.row) ? picked : [last.row];
|
||||
state.cellClip = { field: last.field, values: list.map((i) => rows[i][last.field] ?? null) };
|
||||
const text = state.cellClip.values
|
||||
.map((v) => (last.field === "LineData" ? EstText.display(v ?? "") : (v ?? "")))
|
||||
.join("\n");
|
||||
navigator.clipboard?.writeText(text).catch(() => {});
|
||||
state.notice = `${list.length}칸을 복사했습니다.`;
|
||||
}
|
||||
function paste(state) {
|
||||
if (!last) throw Error("붙여넣을 칸을 먼저 누르세요.");
|
||||
if (!state.cellClip?.values.length) throw Error("복사한 칸이 없습니다.");
|
||||
if (["Code", "SCheck"].includes(last.field))
|
||||
throw Error("코드·결과비목 칸은 셀붙여넣기를 쓸 수 없습니다. 칸에서 직접 고치세요.");
|
||||
const rows = state.project.tables[last.table] || [],
|
||||
numeric = EstModel.numeric.has(last.field);
|
||||
const values = state.cellClip.values.map((v) => {
|
||||
if (!numeric) return v == null ? "" : String(v);
|
||||
const n = v === "" || v == null ? null : Number(v);
|
||||
if (n !== null && !Number.isFinite(n))
|
||||
throw Error("수치 칸에는 수치만 붙여넣을 수 있습니다.");
|
||||
return n;
|
||||
});
|
||||
if (last.row + values.length > rows.length) throw Error("붙여넣을 행이 모자랍니다.");
|
||||
EstApp.change((project) => {
|
||||
const table = project.tables[last.table];
|
||||
values.forEach((v, i) => (table[last.row + i][last.field] = v));
|
||||
});
|
||||
}
|
||||
if (typeof document !== "undefined" && document.addEventListener)
|
||||
document.addEventListener("focusin", (event) => {
|
||||
const t = event.target.closest?.("[data-table][data-field][data-row]");
|
||||
if (t) last = { table: t.dataset.table, row: Number(t.dataset.row), field: t.dataset.field };
|
||||
});
|
||||
function handle(name, state) {
|
||||
if (name === "cell-copy") copy(state);
|
||||
else if (name === "cell-paste") paste(state);
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
return { handle };
|
||||
})();
|
||||
@@ -80,6 +80,7 @@ const allowed = new Set([
|
||||
"native-doc-forms.js",
|
||||
"native-block-file.js",
|
||||
"native-display.js",
|
||||
"native-cell-clip.js",
|
||||
"native-wonga-tools.js",
|
||||
"native-estimate-print.js",
|
||||
"native-xml-check.js",
|
||||
|
||||
Reference in New Issue
Block a user