From b2e2fcff91707937e59f5f1583ec9864dacc041d Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 28 Sep 2026 09:45:50 +0900 Subject: [PATCH] =?UTF-8?q?fix(spreadsheet):=20=EC=97=91=EC=85=80=20?= =?UTF-8?q?=EB=B6=99=EC=97=AC=EB=84=A3=EA=B8=B0=20=EC=84=9C=EC=8B=9D=20?= =?UTF-8?q?=E2=80=94=20=EB=AC=B6=EC=9D=8C=20=EC=84=A0=ED=83=9D=EC=9E=90=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=C2=B7=20=EC=84=A0=20=EA=B5=B5?= =?UTF-8?q?=EA=B8=B0=EB=B3=84=20=EC=A2=85=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ` 안 `.xl65 {...}` 짜임(엑셀이 인라인 대신 클래스로 서식을 실을 때) → 클래스별 선언. */ +/** `` 안 `.xl65 {...}` · `.xl65, .xl70 {...}`(묶음 선택자) 짜임(엑셀이 인라인 대신 + * 클래스로 서식을 실을 때) → 클래스별 선언(같은 클래스가 여러 규칙에 나오면 뒤엣것이 이김). */ function parseClassRules(doc: Document): Record> { const css = Array.from(doc.querySelectorAll("style")) .map((s) => s.textContent ?? "") .join("\n"); const rules: Record> = {}; - for (const m of css.matchAll(/\.([a-zA-Z0-9_-]+)\s*\{([^}]*)\}/g)) { - rules[m[1]] = parseStyleAttr(m[2]); + for (const m of css.matchAll(/([^{}]+)\{([^}]*)\}/g)) { + const decls = parseStyleAttr(m[2]); + for (const selectorPart of m[1].split(",")) { + const cls = /\.([a-zA-Z0-9_-]+)\s*$/.exec(selectorPart.trim()); + if (cls) Object.assign((rules[cls[1]] ??= {}), decls); + } } return rules; } diff --git a/resources/tester/spreadsheet/fixture_excel_style_paste.html b/resources/tester/spreadsheet/fixture_excel_style_paste.html new file mode 100644 index 00000000..139c4167 --- /dev/null +++ b/resources/tester/spreadsheet/fixture_excel_style_paste.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
품목수량금액
터파기1201200000
메우기80800000
합계2002000000
+ + +