// 원본 인쇄범위(TfrmEstPrintRange btnOK 0xcf45e4 — spec_pc §6.4 · spec_print_batch §7): 미리보기에서 부수와 범위를 골라 인쇄. // 현재면 = 미리보기에 보이는 쪽 한 장 × 부수(간지 없음) · 현재항목 전체 = 쪽 범위(0 이면 1~전체) × 부수, 부수마다 간지(그 서식 간지 // 인쇄가 켜져 있으면) · 일괄인쇄 = 묶음 인쇄. 그리고 인쇄양식목록(TfrmEstPrint2 btnFormatList 0xcf9108 → TfrmFormatFileList): // 지금 인쇄표(서식 고르기·간지·용지 설정)를 이름 붙여 보관함(종류 printlist)에 등록하고, 열면 인쇄표를 통째로 바꾼다. const EstPrintRange = (() => { const esc = (v) => String(v ?? "").replace( /[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c], ); const pagesOf = (doc) => [...doc.querySelectorAll("section.page")]; // 범위 고르기: 쪽 목록(0부터) 또는 오류 function pick(total, { mode, current, from, to }) { if (mode === "current") return [Math.min(Math.max(current, 0), total - 1)]; let a = Number(from) || 0, b = Number(to) || 0; if (a === 0) [a, b] = [1, total]; if (b > total) throw Error("인쇄범위가 전체쪽수를 넘었습니다."); if (a > b) throw Error("시작페이지가 끝페이지보다 큽니다."); return Array.from({ length: b - a + 1 }, (_, i) => a - 1 + i); } function panel() { const frame = EstApp.byId("print-frame"), doc = frame?.contentDocument; if (!doc?.body) throw Error("인쇄 미리보기가 준비되지 않았습니다."); const total = Math.max(1, pagesOf(doc).length); let box = EstApp.byId("print-range-box"); if (box) return box.remove(); box = document.createElement("div"); box.id = "print-range-box"; box.className = "business-tools"; box.innerHTML = `인쇄범위 전체쪽수 ${total}쪽 `; frame.before(box); } function run(state) { const box = EstApp.byId("print-range-box"), mode = box.querySelector('[name="pr-mode"]:checked').value; if (mode === "batch") return EstPrintBatch.handle("print-batch", state); const frame = EstApp.byId("print-frame"), doc = frame.contentDocument, pages = pagesOf(doc), copies = Math.max(1, Number(box.querySelector('[data-pr="copies"]').value) || 1); // 현재면: 미리보기 창에 지금 보이는 쪽 const y = frame.contentWindow.scrollY; const current = Math.max( 0, pages.findLastIndex((p) => p.offsetTop <= y + 10), ); const list = pages.length ? pick(pages.length, { mode, current, from: box.querySelector('[data-pr="from"]').value, to: box.querySelector('[data-pr="to"]').value, }) : [0]; const settings = state.project.printSettings || {}, form = (state.project.printCatalog || []).find( (r) => String(r.Index) === String(settings.form), ), gangi = mode === "range" && Number(form?.PrintGangiShow) === 1; const body = pages.length ? list.map((i) => pages[i].outerHTML).join("") : doc.body.innerHTML; const one = (gangi ? `
${esc(form.Name2 || form.Name)}
` : "") + body; const out = doc.documentElement.cloneNode(true); out.querySelector("body").innerHTML = Array.from({ length: copies }, () => one).join(""); let target = EstApp.byId("print-range-frame"); if (!target) { target = document.createElement("iframe"); target.id = "print-range-frame"; target.style.display = "none"; document.body.append(target); } target.onload = () => target.contentWindow.print(); target.srcdoc = "" + out.outerHTML; return { pages: list.length, copies }; } // 인쇄양식목록 const KIND = "printlist"; const post = (body) => ({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); let forms = []; async function list() { forms = (await EstApp.api("/api/forms")).filter((f) => f.kind === KIND); EstApp.showDialog( "인쇄양식목록", ` ${ forms .map( (f) => ``, ) .join("") || '' }
양식 이름등록작업
${esc(f.name)}${esc(String(f.saved || "").slice(0, 10))}
등록된 인쇄양식이 없습니다.
`, ); } const snapshot = (project) => structuredClone({ printCatalog: project.printCatalog, printFormat: project.printFormat, printSettings: project.printSettings, printBatch: project.printBatch, }); function apply(project, data) { for (const k of ["printCatalog", "printFormat", "printSettings", "printBatch"]) if (data[k] === undefined) delete project[k]; else project[k] = structuredClone(data[k]); } async function run2(name, state, node) { if (name === "print-format-list") return list(); if (name === "pfl-register") { const title = prompt("인쇄양식 이름", state.project.name || ""); if (!title?.trim()) return; if ( forms.some((f) => f.name === title.trim()) && !confirm("같은 이름이 있습니다. 덮어 쓰시겠습니까?") ) return; await EstApp.api( "/api/forms", post({ kind: KIND, name: title.trim(), data: snapshot(state.project) }), ); return list(); } const form = forms.find((f) => f.name === node.dataset.name); if (!form) throw Error("양식을 찾을 수 없습니다. 목록을 다시 여세요."); if (name === "pfl-open") { EstApp.change((project) => apply(project, form.data), false); state.notice = `인쇄양식 「${form.name}」을 열었습니다.`; return EstPrintBatch.handle("print-batch", state); } if (!confirm(`「${form.name}」 인쇄양식을 지우시겠습니까?`)) return; await EstApp.api("/api/forms/delete", post({ kind: KIND, name: form.name })); return list(); } function handle(name, state, node) { try { if (name === "print-range") panel(); else if (name === "print-range-ok") run(state); else if (["print-format-list", "pfl-register", "pfl-open", "pfl-delete"].includes(name)) run2(name, state, node).catch((error) => { state.notice = error.message; EstApp.render(); }); else return false; } catch (error) { const note = EstApp.byId("print-error"); if (note) note.textContent = error.message; else throw error; } return true; } return { pick, snapshot, apply, handle }; })();