From 04a432c08a74c4307a138b7d1255822091eb4054 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 12 Nov 2026 19:41:55 +0900 Subject: [PATCH] =?UTF-8?q?feat(est-test):=20=ED=99=98=EA=B2=BD=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=A0=84=EC=B2=B4=20=EC=B0=BD(=ED=83=AD=205=C2=B79?= =?UTF-8?q?2=EC=B9=B8,=20=EC=A0=81=EC=9A=A9=20=EC=95=8C=EB=A6=BC=C2=B7?= =?UTF-8?q?=EC=88=9C=EA=B3=B5=EC=82=AC=EB=B9=84=20=EB=AA=85=EC=B9=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 웹 계산·표시 옵션에 이어진 칸은 그 옵션에, 나머지는 값만, PC 설정은 브라우저에 - 바꾼 칸만 씀, 원본 적용 알림 - 코드표시 켜면 표에 코드 열, 레벨 표시 끄면 레벨 열 뺌 Co-Authored-By: Claude Opus 5.5 --- resources/tester/helper_est_native.cjs | 1 + resources/tester/test_est_option_all.py | 26 +++ tools/est-test/PLAN.md | 2 + tools/est-test/index.html | 1 + tools/est-test/native-actions-more.js | 1 + tools/est-test/native-actions.js | 4 +- tools/est-test/native-display.js | 5 + tools/est-test/native-option-all.js | 282 ++++++++++++++++++++++++ tools/est-test/server.cjs | 1 + 9 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 resources/tester/test_est_option_all.py create mode 100644 tools/est-test/native-option-all.js diff --git a/resources/tester/helper_est_native.cjs b/resources/tester/helper_est_native.cjs index a389e3db4..3d1339ebf 100644 --- a/resources/tester/helper_est_native.cjs +++ b/resources/tester/helper_est_native.cjs @@ -41,6 +41,7 @@ for (const file of [ "native-work-mode.js", "native-dongwon-check.js", "native-excel-files.js", + "native-option-all.js", "native-business-actions.js", "native-forms.js", "native-excel-to-est.js", diff --git a/resources/tester/test_est_option_all.py b/resources/tester/test_est_option_all.py new file mode 100644 index 000000000..8468a7e2c --- /dev/null +++ b/resources/tester/test_est_option_all.py @@ -0,0 +1,26 @@ +"""환경설정 전체: 읽기 기본값·바뀐 칸만 쓰기·옵션 자리(계산·표시·기성·Env).""" + +from test_est_rea_parity import run + + +def test_write_only_changed_fields_to_their_places(): + result = run( + "math", + """(()=>{ + const A=EstOptionAll, item=(k)=>A.TABS.flatMap(t=>t[1]).find(i=>i.k===k); + const o={HeadDigits:2,VerFormat:true,CostValueTrunc:false,AutoCalc:true}; + const r0={head:A.read(o,item('headDigits')),fmt:A.read(o,item('format')),code:A.read(o,item('code')), + total:A.read(o,item('totalName'))}; + A.write(o,{headDigits:1,format:1,code:true,level:true,jabbi:true,costMethod:1,recalc:2,twoLine:1}); + return {r0,o}; + })()""", + ) + assert result["r0"] == {"head": 1, "fmt": 0, "code": False, "total": "순공사비"} + o = result["o"] + assert o["HeadDigits"] == 2 # 1 → 1 그대로(바뀌지 않음) + assert o["VerFormat"] is False + assert o["CostValueTrunc"] is True + assert o["OldRecalcMethod"] == 2 + assert o["Display"] == {"code": True, "twoLine": True} + assert o["AccomOption"] == {"level": True} + assert o["Env"] == {"jabbi": True} diff --git a/tools/est-test/PLAN.md b/tools/est-test/PLAN.md index 974633e6a..95815d716 100644 --- a/tools/est-test/PLAN.md +++ b/tools/est-test/PLAN.md @@ -510,6 +510,8 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD - 검증완료: 확인 시험 1개·동원 관련 시험 35개 통과. ORCA 브라우저에서 일위 8건 모두 일치·당초값=계산값, 항목 3개 표시. - [x] 엑셀물량 파일목록(TfrmExcelMullang btnNewProject·btnDelete · spec_pa §7) — 공사에 딸린 엑셀 물량 파일을 작업에 담음(Index·파일명). 추가 = 파일 골라 목록에(같은 이름 거부 — 원본은 엑셀에 띄우기만, 웹은 엑셀이 없어 여기서 등록) · 삭제 = 확인 뒤 목록·담은 파일 지움(셀 연결은 남음) · 열기 = 내려받기. 셀 수량 연결 창에서 목록 파일을 골라 쓰고, 새 파일로 연결하면 목록에 들어감. ESTX 저장은 JSON 안내. - 검증완료: 파일목록 시험 1개·수량산출 시험 6개 통과. ORCA 브라우저에서 목록 등록 → 목록 파일로 B2 셀 연결(수량 12.5)·연결 수 1 → 삭제 확인, 원복. + - [x] 환경설정 전체 창(TfrmOption btnLoad · spec_pb2 §9) — 탭 다섯(공통적용·내역서·일위단산기계·표준자재원가·설계변경수량심사) 92칸. 웹 계산·표시에 이어진 칸은 그 옵션에(일위 자리수·단산 금액란·중간 자리수·외화 절하·재료비 처리·이윤 사사오입·관급 조달수수료·원가 방향·자동계산·재계산 범위·정산금액·비목순서·정렬·두줄·Enter·코드 열·0 표시·바탕색·레벨·발췌근거·집계 진하게), 나머지는 값만(Env), PC 설정은 이 브라우저. 바꾼 칸만 씀. 적용 때 원본 알림(자동계산 끔/켬·표준단가비목·조달청 계산방식·산식 표시·공종+품명 합치기)과 순공사비 명칭 바꾸면 순공사비 행 이름도 바꿈. 기성 화면에서는 기성 환경설정. 순공사비 상단/하단 이동·제잡비 행 넣기는 값만(웹 계산이 순공사비 위치를 아래로 가정). + - 검증완료: 환경설정 시험 1개·표시·기성 시험 4개 통과. ORCA 브라우저에서 탭 5·칸 92, 코드표시 켬 → 자재 표에 코드 열, 순공사비 명칭 → 행 이름 바뀜, 원복. - [x] 다른 공사 불러오기 창(원본 barbtnSelfLoad → TfrmOtherLoad, 찾기 popSerch) — 저장된 다른 작업을 골라 같은 표를 띄우고 찾기(품명·규격, A&B 둘 다)·고른 줄을 하위 자료와 함께 가져오기(내역서는 고른 줄 아래에 줄, 나머지는 자료·호표 합침, 같은 코드는 이 공사 것). 검증완료: 바인딩 통과, ORCA 브라우저에서 산불진화임도 작업의 일위대가 3개 → 「취수장」 1개 → 가져오기 호표 8→9·하위 41건, 샘플 복구. - [x] 사용위치 검색 창(원본 TfrmUsesDataSerch btnSerch·btnAllDisplay) — 현재 표 항목을 품명·규격(빈칸·|·괄호 무시)으로 거르고 골라 사용위치 보기. 검증완료: 바인딩 통과, ORCA 브라우저에서 노임 9개 → 「보 통」 1개 → 보통인부 사용위치 11곳. - [x] 인쇄양식 불러오기·저장하기(원본 mnuPrintFormatLoad·Save 0x10ed318·0x10ed000 — spec_pc §3) — .pfot(인쇄정보표 MIDAS 이진) 읽기·쓰기 `print-format.cjs`(설명 BLOB·빈 칸 표지까지 보존, 원본 파일 그대로 다시 쓰면 바이트 같음). 불러오면 공사 인쇄표를 그 값으로, 저장은 지금 인쇄표를 원본 설치 main.pfot 필드 설명자 위에(`EST_PFOT_TEMPLATE`). .gfot(cxGrid 열 배치)는 웹 격자와 호환되지 않아 하지 않음. diff --git a/tools/est-test/index.html b/tools/est-test/index.html index 40cd07137..828186127 100644 --- a/tools/est-test/index.html +++ b/tools/est-test/index.html @@ -29,6 +29,7 @@ + diff --git a/tools/est-test/native-actions-more.js b/tools/est-test/native-actions-more.js index 30ca6eaf2..d7e50de69 100644 --- a/tools/est-test/native-actions-more.js +++ b/tools/est-test/native-actions-more.js @@ -14,6 +14,7 @@ const EstActionsMore = (() => { typeof EstWorkMode !== "undefined" && EstWorkMode, typeof EstDongwonCheck !== "undefined" && EstDongwonCheck, typeof EstExcelFiles !== "undefined" && EstExcelFiles, + typeof EstOptionAll !== "undefined" && EstOptionAll, ].filter(Boolean); function handle(name, state, node) { for (const module of modules()) if (module.handle(name, state, node)) return true; diff --git a/tools/est-test/native-actions.js b/tools/est-test/native-actions.js index 3dae41fab..0198a9554 100644 --- a/tools/est-test/native-actions.js +++ b/tools/est-test/native-actions.js @@ -334,7 +334,9 @@ const EstActions = (() => { `

${result.checked}개 중 ${result.passed}개 일치 · 불일치 ${result.failed}개

보관된 EST 샘플의 저장값과 계산 결과를 비교했습니다. 원본 실행 비교는 포함하지 않습니다.

${result.errors.length ? `

${esc(result.errors.join(" / "))}

` : ""}${[...new Set(result.results.map((r) => r.group))].map((group) => ``).join("")}
영역검사 수일치
${esc(group)}${result.results.filter((r) => r.group === group).length}${result.results.filter((r) => r.group === group && r.pass).length}
`, ); } else if (name === "settings") - EstApp.state.view === "progress" ? EstProgressView.dialog(EstApp.state) : EstSettings.show(); + EstApp.state.view === "progress" + ? EstProgressView.dialog(EstApp.state) + : EstOptionAll.dialog(EstApp.state); else if (name === "raw-line") { const row = activeRows()[Number(node.dataset.row)]; showDialog( diff --git a/tools/est-test/native-display.js b/tools/est-test/native-display.js index 916fb1a20..07103b5a7 100644 --- a/tools/est-test/native-display.js +++ b/tools/est-test/native-display.js @@ -22,6 +22,11 @@ const EstDisplay = (() => { function columns(options, cols) { const d = get(options); let out = d.gubun ? cols : cols.filter((k) => k !== "ValueIndex"); + // 코드표시(CommonCheckCode): 켜면 품명 앞에 코드 열, 끄면 뺌(웹 표는 처음에 코드 열이 없음) + if (d.code === false) out = out.filter((k) => k !== "Code"); + else if (d.code === true && !out.includes("Code") && out.includes("Name")) + out = out.flatMap((k) => (k === "Name" ? ["Code", k] : [k])); + if (options?.AccomOption?.level === false) out = out.filter((k) => k !== "Level"); // 레벨 표시 끔 const order = ORDERS[d.order]; if (!order || d.order === 0) return out; for (const suffix of ["C", "U"]) { diff --git a/tools/est-test/native-option-all.js b/tools/est-test/native-option-all.js new file mode 100644 index 000000000..ce2ca59c0 --- /dev/null +++ b/tools/est-test/native-option-all.js @@ -0,0 +1,282 @@ +// 원본 환경설정 TfrmOption 「적 용」(btnLoad 0xd034f8 → FormClose 후처리 d03d20 — spec_pb2 §9): 탭별 칸 전부. +// 웹 계산·표시에 이어진 칸은 그 옵션(HeadDigits·CostValueTrunc·MidCostDiget·DollarCostCut·GCToWonga·EYunUp· +// GangubExceptJodalRatio·VerFormat·AutoCalc·OldRecalcMethod·JungSangShow·Display·AccomOption)에 쓰고, 나머지는 계산 환경 Env 에 +// 값만 담는다. PC 설정(INI: 자동저장 분·백업·새이름 공사명·불러오기창·찾을문자크기·금액 변경확인·자재 틀고정)은 이 브라우저에. +// 적용 때 원본 알림: 자동계산 끔/켬 · 표준단가비목 · 조달청 계산방식 · 산식 표시 · 공종+품명 합치기 · 순공사비 명칭(행 이름 바꿈). +const EstOptionAll = (() => { + const num = (v) => Number(v) || 0; + const PC = "est-pc-options"; + const yes = (k, label, at, def = false) => ({ k, label, kind: "check", at, def }); + const pick = (k, label, choices, at, def = 0) => ({ k, label, kind: "pick", choices, at, def }); + const int = (k, label, min, max, at, def = 0) => ({ k, label, kind: "int", min, max, at, def }); + const text = (k, label, at, def = "") => ({ k, label, kind: "text", at, def }); + const ORDER = [ + "합/노/재/경", + "합/재/노/경", + "노/재/경/합", + "재/노/경/합", + "합/경/재/노", + "경/재/노/합", + ]; + const GUNGU = [ + "일위대가", + "단가산출", + "기계경비", + "표준단가", + "견적단가", + "자재단가", + "노임단가", + ]; + // at: "opt:키"(계산 옵션) · "disp:키"(Display) · "accom:키"(AccomOption) · "pc"(이 브라우저) · 없음 = Env + const TABS = [ + [ + "공통적용", + [ + pick("order", "비목순서", ORDER, "disp:order"), + pick("align", "품명정렬", ["좌정렬", "우정렬", "중앙정렬"], "disp:align"), + pick("twoLine", "품명표기", ["한줄로 표시", "두줄로 표시"], "disp:twoLine"), + pick("enter", "Enter 후 셀 이동", ["이동안함", "좌", "우", "위", "아래"], "disp:enter"), + yes("code", "코드표시", "disp:code"), + yes("gnZero", '수량 "0" 표시', "disp:gnZero", true), + yes("costZero", '금액 "0" 표시', "disp:costZero", true), + int("gnDigits", "수량 표시 자리수", 0, 6, null, 3), + int("nachalDigits", "낙찰율 표시 자리수", 0, 6, null, 2), + yes("nachalShow", "낙찰율 표시"), + yes("haljungShow", "할증율 표시"), + yes("siljukBimog", "표준단가비목표시"), + yes("autoSave", "데이타 자동저장", "disp:autoSave"), + int("saveTime", "자동저장 분", 5, 30, "pc", 10), + yes("siljukSearch", "표준단가 동시검색"), + yes("numSort", "공종일련번호 자동정렬"), + yes("jodalMethod", "조달청 계산방식적용"), + yes("nameMatch", "명칭 불일치 검색"), + yes("valueCompare", "신,구 단가비교 보기"), + int("searchLength", "찾을문자크기", 1, 20, "pc", 2), + text("color", "바탕색(#rrggbb)", "disp:color"), + yes("backup", "백업 저장", "pc"), + yes("projectAutoChange", "새이름 저장 시 공사명 변경", "pc"), + yes("searchFormAuto", "불러오기창 위치 기억", "pc"), + ], + ], + [ + "내역서", + [ + pick("nameShow", "공종 표시", ["공종=(공종+품명)", "별도"], null, 1), + yes("gungu", "비고란에 발췌근거 표시", "accom:gungu"), + yes("level", "레벨 표시", "accom:level"), + yes("projectTop", "공사명 설계서 첫줄에 표시"), + yes("titleTopPrint", "공사명 총괄표 첫줄에 인쇄"), + yes("jabbi", "내역서에 제잡비 표시"), + yes("sumBold", "집계공종 진하게", "accom:sumBold"), + yes("nachalGubun", "낙찰율 노,재,경 구분 표시"), + pick("totalPos", "순공사비 계산 위치", ["하단", "상단"]), + text("totalName", "순공사비 명칭", null, "순공사비"), + yes("firstTotal", "새공사 시작시 순공사비 자동생성", null, true), + pick("horCalc", "데이타(가로) 계산방법", ["절하", "절상"], "accom:horCalc"), + yes("calcCheck", "가로,세로 계산 확인", "accom:calcCheck"), + yes("calcAuto", "내역서 자동계산", "opt:AutoCalc", true), + yes("costCompareMsg", "재계산후 공사금액 변경확인", "pc"), + ...GUNGU.map((g, i) => yes(`gungu${i}`, `발췌근거 표시 — ${g}`)), + ], + ], + [ + "일위·단산·기계", + [ + pick("headDigits", "일위대가 금액 계산 자리수", ["원단위", "소수1위"], "opt:HeadDigits"), + pick("headHorCalc", "일위대가 데이타(가로) 계산방법", ["절하", "절상"]), + yes("headBigo", "일위대가 비고란 발췌근거"), + yes("headInfo", "일위대가 공종 정보창"), + pick("costMethod", "단가산출 금액란", ["소수1위", "절하"], "opt:CostValueTrunc"), + int("midCost", "단가산출 중간계산 결과값 자리수", 0, 6, "opt:MidCostDiget", 2), + yes("sansic", "수식을 산식으로 변환 표시"), + yes("susicCheck", "수식오류 검색"), + yes("linkValueEdit", "연결 항목 편집허용"), + yes("costShowToHead", "공종 라인 총단가"), + yes("costInfo", "단가산출 정보창"), + yes("dollarCut", "외화장비 손료 1,000단위 미만 절하", "opt:DollarCostCut"), + yes("machInfo", "기계경비 정보창"), + ], + ], + [ + "표준·자재·원가", + [ + pick("remainBimog", "노무비율계산후 잔여단가 적용비목", ["재료비", "경비"]), + yes("siljukCode", "표준단가 비고란 코드"), + yes("stuffcGungu", "자재 비고란 발췌근거"), + yes("stuffcFixed", "자재 품명,규격 틀고정", "pc"), + pick("gcTo", "순직접공사비의 재료비", ["간접재료비", "직접재료비"], "opt:GCToWonga"), + yes("eyun", "이윤 비율 사사오입", "opt:EYunUp"), + yes("gangub", "안전관리비 관급자재대 조달수수료 제외", "opt:GangubExceptJodalRatio"), + yes("digetOldCost", "자리수 조정후 수식에 원금액 표시"), + yes("jungsan", "정산금액 표시", "opt:JungSangShow"), + pick("format", "원가계산서 양식 방향", ["세로", "가로"], "opt:VerFormat"), + yes("selectPrint", "원가 선택항목만 인쇄"), + ], + ], + [ + "설계변경·수량·심사", + [ + pick("changeOrder", "상단·하단", ["상단=당초 · 하단=변경", "상단=변경 · 하단=당초"]), + text("upText", "상단 표시문자", null, "당초"), + text("downText", "하단 표시문자", null, "변경"), + yes("upBold", "상단 굵게 인쇄"), + yes("downBold", "하단 굵게 인쇄"), + pick("nameShowMethod", "공종,품명,규격", ["변경만", "당초,변경 모두", "다르면 둘다"]), + pick("gunguShowMethod", "근거자료", ["신규만", "전부"]), + yes("oldCostShow", "신규공종 당초단가 표시"), + yes("nachalAuto", "신규공종 낙찰율 자동계산"), + yes("nachalToBigo", "비고란에 낙찰율 표시"), + pick("recalc", "재계산", ["신규만", "변경단가만", "전체"], "opt:OldRecalcMethod"), + yes("changeZero", "변경금액만 0 표시"), + yes("cellMerge", "증감 셀 병합"), + yes("mnsShow", "감 부호(-) 표시"), + yes("changeBigo", "변경 비고란 표시"), + yes("changeCalcAuto", "변경 내역서 자동계산", null, true), + pick("mulCalc", "수량산출 계산결과값", ["사사오입", "절하", "절상"]), + int("mulDigits", "수량산출 소수이하 자리수", 0, 6, null, 3), + yes("mulSansic", "수량산출 산식 변환"), + yes("mulColor", "도면칼라 인쇄"), + pick("investPrint", "계약심사 인쇄방법", ["내역서 양식", "설계변경 양식"]), + pick("investItems", "계약심사 인쇄항목", ["전부", "변경만"]), + ], + ], + ]; + const ALL = TABS.flatMap(([, items]) => items); + + const pc = () => JSON.parse(localStorage.getItem(PC) || "{}"); + // 지금 값 읽기 + function read(options, item) { + const [where, key] = String(item.at || "").split(":"); + let v; + if (where === "opt") v = options[key]; + else if (where === "disp") v = options.Display?.[key]; + else if (where === "accom") v = options.AccomOption?.[key]; + else if (where === "pc") v = typeof localStorage !== "undefined" ? pc()[item.k] : undefined; + else v = options.Env?.[item.k]; + if (item.k === "format") return v === false ? 1 : 0; // VerFormat true = 세로 + if (item.k === "headDigits") return num(v) > 0 ? 1 : 0; + if (item.k === "twoLine") return v ? 1 : 0; + return v ?? item.def; + } + // 고친 값 → 옵션 쓰기(project.options 를 직접 고침). pcOut 은 이 브라우저 값 + function write(options, values, pcOut = {}) { + for (const item of ALL) { + if (!(item.k in values)) continue; + let v = values[item.k]; + // 바꾼 칸만 씀(웹 고유 값 — 예: 일위 자리수 2 — 을 그대로 두게) + const now = read(options, item); + if ( + item.kind === "check" + ? Boolean(now) === Boolean(v) + : item.kind === "text" + ? String(now ?? "") === String(v) + : num(now) === num(v) + ) + continue; + if (item.kind === "check") v = Boolean(v); + else if (item.kind !== "text") v = num(v); + if (item.k === "format") v = v === 0; + if (item.k === "twoLine") v = v === 1; + if (["costMethod", "gcTo"].includes(item.k)) v = v === 1; + const [where, key] = String(item.at || "").split(":"); + if (where === "opt") options[key] = v; + else if (where === "disp") options.Display = { ...(options.Display || {}), [key]: v }; + else if (where === "accom") + options.AccomOption = { ...(options.AccomOption || {}), [key]: v }; + else if (where === "pc") pcOut[item.k] = v; + else options.Env = { ...(options.Env || {}), [item.k]: v }; + } + return pcOut; + } + + let tab = 0; + function dialog(state) { + const { esc } = EstApp, + o = state.project.options; + const field = (item) => { + const v = read(o, item); + if (item.kind === "check") + return ``; + if (item.kind === "pick") + return ``; + if (item.kind === "int") + return ``; + return ``; + }; + EstApp.showDialog( + "환경설정", + `
${TABS.map(([name], i) => ``).join("")}
${TABS.map(([, items], i) => `
${items.map(field).join("")}
`).join("")}

`, + ); + } + function collect() { + const values = {}; + for (const node of document.querySelectorAll("#dialog-content [data-oa]")) + values[node.dataset.oa] = node.type === "checkbox" ? node.checked : node.value; + for (const item of ALL) + if (item.kind === "int") { + const v = Number(values[item.k]); + if (!Number.isInteger(v) || v < item.min || v > item.max) + throw Error(`${item.label}은(는) ${item.min}~${item.max} 정수입니다.`); + } + if (values.color && !/^#[0-9a-f]{6}$/i.test(values.color)) + throw Error("바탕색은 #rrggbb 꼴입니다."); + return values; + } + // 적용(d03d20 후처리): 알림과 자료 반영 + function apply(state) { + const values = collect(), + before = state.project.options, + notes = []; + const was = (k) => + read( + before, + ALL.find((i) => i.k === k), + ); + if (was("calcAuto") && !values.calcAuto && !confirm("내역서의 모든 계산기능이 해제됩니다.")) + values.calcAuto = true; + if (!was("calcAuto") && values.calcAuto) notes.push("내역서를 재계산 시켜주세요."); + if (Boolean(was("siljukBimog")) !== values.siljukBimog) + notes.push("반드시 재계산을 시켜야 금액이 정상적으로 표시됩니다."); + if (Boolean(was("jodalMethod")) !== values.jodalMethod) notes.push("전체 재계산을 해주세요."); + if (Boolean(was("sansic")) !== values.sansic) notes.push("일건서류 전체를 재계산 합니다."); + if ( + num(was("nameShow")) === 1 && + num(values.nameShow) === 0 && + !confirm("공종과 품명을 합치면 되돌릴수 없습니다.") + ) + values.nameShow = 1; + const rename = String(values.totalName ?? "").trim() && values.totalName !== was("totalName"); + let pcOut; + EstApp.change((project) => { + pcOut = write(project.options, values); + if (rename) + for (const row of project.tables.EstMainDat) + if (num(row.LinkIndex) === 54) row.Name = values.totalName.trim(); + }); + localStorage.setItem(PC, JSON.stringify({ ...pc(), ...pcOut })); + EstApp.byId("dialog").close(); + state.notice = notes.join(" ") || "환경설정을 적용했습니다."; + EstApp.render(); + } + + function handle(name, state, node) { + if (name === "option-all") dialog(state); + else if (name === "option-all-tab") { + tab = Number(node.dataset.tab); + for (const box of document.querySelectorAll("#dialog-content [data-oa-tab]")) + box.hidden = Number(box.dataset.oaTab) !== tab; + for (const b of document.querySelectorAll('[data-action="option-all-tab"]')) + b.setAttribute("aria-pressed", String(Number(b.dataset.tab) === tab)); + } else if (name === "option-all-apply") + try { + apply(state); + } catch (error) { + EstApp.byId("option-all-error").textContent = error.message; + } + else if (name === "option-all-cancel") EstApp.byId("dialog").close(); + else if (name === "option-all-web") EstSettings.show(); + else return false; + return true; + } + return { TABS, read, write, handle, dialog }; +})(); diff --git a/tools/est-test/server.cjs b/tools/est-test/server.cjs index 80503723f..d0796aff7 100644 --- a/tools/est-test/server.cjs +++ b/tools/est-test/server.cjs @@ -113,6 +113,7 @@ const allowed = new Set([ "native-work-mode.js", "native-dongwon-check.js", "native-excel-files.js", + "native-option-all.js", "native-actions-more.js", "native-wonga-tools.js", "native-estimate-print.js",