Initial commit
This commit is contained in:
419
skills/docx/references/common-rules.md
Executable file
419
skills/docx/references/common-rules.md
Executable file
@@ -0,0 +1,419 @@
|
||||
# Common Rules
|
||||
|
||||
Shared rules referenced by all scene files. Scene-specific overrides take precedence.
|
||||
|
||||
## Default Page Layout
|
||||
|
||||
A4 portrait. Unless the scene specifies otherwise, use:
|
||||
|
||||
| Property | Value | Twips |
|
||||
|----------|-------|-------|
|
||||
| Page width | 21.0 cm | 11906 |
|
||||
| Page height | 29.7 cm | 16838 |
|
||||
| Top margin | 2.54 cm | 1440 |
|
||||
| Bottom margin | 2.54 cm | 1440 |
|
||||
| Left margin | 3.0 cm | 1701 |
|
||||
| Right margin | 2.5 cm | 1417 |
|
||||
|
||||
```js
|
||||
page: {
|
||||
size: { width: 11906, height: 16838, orientation: PageOrientation.PORTRAIT },
|
||||
margin: { top: 1440, bottom: 1440, left: 1701, right: 1417 },
|
||||
}
|
||||
```
|
||||
|
||||
**Scene overrides:**
|
||||
- **Official doc (GB/T 9704 red-header):** top 2098, bottom 1984, left 1588, right 1474
|
||||
- **Exam:** top/bottom 1134 (2 cm), left/right 1134 (2 cm)
|
||||
|
||||
## Default Font Specifications
|
||||
|
||||
Two font profiles exist. Each scene declares which profile it uses.
|
||||
|
||||
### Profile A: Formal (report, academic, contract, official-doc, exam)
|
||||
|
||||
| Element | CN Font | EN Font | Size | Notes |
|
||||
|---------|---------|---------|------|-------|
|
||||
| H1 | SimHei | Times New Roman | 16 pt (size: 32) | Bold, centered |
|
||||
| H2 | SimHei | Times New Roman | 15 pt (size: 30) | Bold |
|
||||
| H3 | SimHei | Times New Roman | 14 pt (size: 28) | Bold |
|
||||
| Body | SimSun | Times New Roman | 12 pt (size: 24) | |
|
||||
| Caption | SimSun | Times New Roman | 10.5 pt (size: 21) | |
|
||||
|
||||
- Text color: always **pure black `"000000"`** (never dark-blue-grey)
|
||||
- First-line indent: **480 twips** (2 chars at SimSun 12pt)
|
||||
- Line spacing: **312** (1.3x).
|
||||
- **Color routing for non-report documents**: When the document is a short-form text (essay, evaluation, letter, speech, application, reflection, etc.) rather than a structured report/whitepaper/proposal/consulting deliverable, heading color MUST use pure black `"000000"` instead of `palette.primary`. Colored headings are reserved for documents that need brand/professional identity (reports with covers, whitepapers, proposals, consulting deliverables).
|
||||
|
||||
### Profile B: Visual (resume, copywriting)
|
||||
|
||||
| Element | CN Font | EN Font | Size |
|
||||
|---------|---------|---------|------|
|
||||
| Name/Title | Microsoft YaHei | Calibri | Varies |
|
||||
| Body | Microsoft YaHei | Calibri | 10–11 pt |
|
||||
| Caption | Microsoft YaHei | Calibri | 9 pt |
|
||||
|
||||
- First-line indent: **420 twips** (2 chars at YaHei)
|
||||
- Color: per design-system palette
|
||||
|
||||
### Official-Doc Font Override (GB/T 9704)
|
||||
|
||||
When `needsRedHeader() = true`:
|
||||
|
||||
| Element | Font | Size |
|
||||
|---------|------|------|
|
||||
| Red header org name | STXiaoBiaoSong (or SimSun bold) | 26 pt (size: 52) |
|
||||
| Title | STXiaoBiaoSong (or SimHei) | 22 pt (size: 44) |
|
||||
| Body | FangSong | 16 pt (size: 32) |
|
||||
| Section heading | FangSong_GB2312 bold (or HeiTi) | 16 pt (size: 32) |
|
||||
|
||||
- Line spacing: **560** (28 pt fixed)
|
||||
- First-line indent: **640 twips** (2 chars at FangSong 16pt)
|
||||
|
||||
## Chinese Font Size Reference
|
||||
|
||||
| Name | Points | Half-points (size:) |
|
||||
|------|--------|---------------------|
|
||||
| Chu Hao (initial) | 42 | 84 |
|
||||
| Xiao Chu | 36 | 72 |
|
||||
| Yi Hao (1st) | 26 | 52 |
|
||||
| Xiao Yi | 24 | 48 |
|
||||
| Er Hao (2nd) | 22 | 44 |
|
||||
| Xiao Er | 18 | 36 |
|
||||
| San Hao (3rd) | 16 | 32 |
|
||||
| Xiao San | 15 | 30 |
|
||||
| Si Hao (4th) | 14 | 28 |
|
||||
| Xiao Si | 12 | 24 |
|
||||
| Wu Hao (5th) | 10.5 | 21 |
|
||||
| Xiao Wu | 9 | 18 |
|
||||
| Liu Hao (6th) | 7.5 | 15 |
|
||||
|
||||
## Placeholder Convention
|
||||
|
||||
When required information is missing, use standardized placeholders so users can Find & Replace in Word.
|
||||
|
||||
**Format:** Always use full-width brackets `【 】`.
|
||||
|
||||
| Type | Format | Example |
|
||||
|------|--------|---------|
|
||||
| General field | `【field name】` | Name: 【company name】 |
|
||||
| Monetary amount | `【RMB in words: yuan (lowercase: ¥)】` | Amount: 【RMB in words】 |
|
||||
| Date field | `【____/____/____】` | Signing date: 【____/____/____】 |
|
||||
| Long text | `【Please fill in: ______】` | Delivery criteria: 【Please fill in: ______】 |
|
||||
| Attachment ref | `【See Appendix 1: ______】` | |
|
||||
|
||||
**Rules:**
|
||||
1. Placeholder format must be consistent throughout the entire document
|
||||
2. Each placeholder must specify exactly what is needed (never use vague "TBD" or "to be completed")
|
||||
3. Never hard-code unconfirmed critical facts; use a placeholder instead
|
||||
4. Never use sloppy expressions like "to be refined", "omitted", "user fills in later"
|
||||
|
||||
## Title Orphan Prevention (All Scenes)
|
||||
|
||||
Body headings (H1/H2/H3) and cover titles must avoid leaving 1–2 characters alone on the last line. This rule applies to ALL document types.
|
||||
|
||||
**For cover titles:** Always use `calcTitleLayout()` + `splitTitleLines()` from `design-system.md` — these handle orphan prevention automatically (merges ≤2-char last lines into the previous line).
|
||||
|
||||
**For body headings (H1/H2/H3):** When a heading text is long enough to wrap, apply the same `splitTitleLines()` logic. If the heading would cause a single-character orphan in Word's auto-wrapping, manually split into multiple `TextRun` elements with a `Break` (soft line break) at a semantic boundary.
|
||||
|
||||
```js
|
||||
const { Break } = require("docx");
|
||||
|
||||
// Check if heading needs manual line break to prevent orphan
|
||||
function buildHeadingRuns(text, maxCharsPerLine, runProps) {
|
||||
// If text fits in one line, no action needed
|
||||
if (text.length <= maxCharsPerLine) {
|
||||
return [new TextRun({ text, ...runProps })];
|
||||
}
|
||||
// Use splitTitleLines to find semantic break points
|
||||
const lines = splitTitleLines(text, maxCharsPerLine);
|
||||
const runs = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (i > 0) runs.push(new TextRun({ break: 1, ...runProps, text: "" })); // soft line break
|
||||
runs.push(new TextRun({ text: lines[i], ...runProps }));
|
||||
}
|
||||
return runs;
|
||||
}
|
||||
```
|
||||
|
||||
**Estimation for maxCharsPerLine:** For centered headings, estimate available width = page width - left margin - right margin. For SimHei at a given pt size, each CJK char ≈ pt × 20 twips wide. Divide available width by char width to get `maxCharsPerLine`.
|
||||
|
||||
---
|
||||
|
||||
## Undefined / Null Value Prevention (Mandatory)
|
||||
|
||||
Generated code MUST guard against outputting literal `undefined`, `null`, `NaN`, or empty strings for any visible text field. This is a **hard requirement** — these are never acceptable in a delivered document.
|
||||
|
||||
```js
|
||||
// ✅ MANDATORY: Safe text helper — use for ALL user-facing text values
|
||||
function safeText(value, placeholder) {
|
||||
if (value === undefined || value === null || value === "" || String(value) === "NaN" || String(value) === "undefined") {
|
||||
return placeholder || "【Please fill in】";
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
|
||||
// Usage:
|
||||
new TextRun({ text: safeText(config.contact, "【Contact person】") })
|
||||
new TextRun({ text: safeText(row.phone, "【Phone number】") })
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
1. Every `TextRun` displaying user-provided or config-derived data MUST use `safeText()` or equivalent guard
|
||||
2. If a field is optional and not provided, use `【Please fill in: field_name】` placeholder (full-width brackets)
|
||||
3. Table cells with missing data: show `【Please fill in】`, never leave as empty string or undefined
|
||||
4. This applies to ALL scenes — contracts, reports, academic, exams, etc.
|
||||
|
||||
---
|
||||
|
||||
## WPS / Office Word Compatibility (Mandatory)
|
||||
|
||||
Generated .docx files must render consistently in both Microsoft Office Word and WPS Office. The following OOXML features have known compatibility issues — avoid or use carefully.
|
||||
|
||||
### Features to AVOID (high incompatibility risk)
|
||||
|
||||
| Feature | Issue | Alternative |
|
||||
|---------|-------|------------|
|
||||
| **Text-character decorative lines** (e.g., `───`, `━━━`, `═══`, `——————`) | Character-drawn lines depend on font metrics and rendering engine — they appear different widths/lengths in MS Office vs WPS, often truncated or misaligned. They cannot span a controlled width. | **Always use paragraph borders** (`border.top`, `border.bottom`) for horizontal decorative lines. Paragraph borders render consistently across engines and respect indent for precise width control. See recipe R2 for correct implementation. |
|
||||
| **Default table borders on cover wrapper tables** (forgetting `allNoBorders`) | docx-js default table borders are `single/auto/sz=4`. On the 16838-high cover wrapper, these borders add ~8 twips of extra height per edge. MS Office includes border thickness in height calculation, causing content to overflow by a few twips → **blank page 2**. WPS is more lenient and may absorb the overflow. | **Every cover wrapper table MUST explicitly set `borders: allNoBorders`** (all 6 border positions = NONE). Never rely on defaults. Define the `allNoBorders` constant and use it consistently. |
|
||||
| `verticalAlign: "center"` or `"bottom"` in exact-height TableRow | WPS ignores vertical alignment in exact-height rows; content may clip or shift | Use `verticalAlign: "top"` + `spacing.before` to position content. Avoid `margins.top`/`margins.bottom` in exact-height cells — they reduce available height unpredictably across engines |
|
||||
| `characterSpacing` (large values) | WPS renders differently from Word; letter spacing may collapse or expand | Keep `characterSpacing` ≤ 80; for cover English labels, test both renderers |
|
||||
| `margins.top`/`margins.bottom` inside exact-height cells | MS Office and WPS calculate remaining height differently when cell margins are present | Use `spacing.before` on the first paragraph for vertical positioning; only use `margins.left`/`margins.right` |
|
||||
| Complex nested Tables inside exact-height cells | WPS height calculation differs from Word; content may overflow or clip | Wrap everything in a single 16838 outer wrapper cell (R1 architecture). Nested tables inside are acceptable when the outer wrapper provides a safety net |
|
||||
| Large font without explicit `spacing.line` | Paragraph inherits small line spacing from document default (e.g., 560tw for body); font taller than line height → top of characters clipped | Always set `spacing: { line: fontPt * 23, lineRule: "atLeast" }` on paragraphs with font size > body text |
|
||||
| `ShadingType.SOLID` | WPS shows solid black instead of intended color | Always use `ShadingType.CLEAR` |
|
||||
| OOXML raw XML for columns (`w:cols`) | WPS column rendering may differ | Use only when explicitly needed (A3 exam papers); test output |
|
||||
| `titlePage: true` with complex headers/footers | WPS may not properly suppress first-page header/footer | Use separate sections instead of titlePage flag |
|
||||
| Tab stops for alignment | WPS tab width may differ from Word | Use borderless Tables for alignment instead |
|
||||
|
||||
### Features that are SAFE (consistent rendering)
|
||||
|
||||
| Feature | Notes |
|
||||
|---------|-------|
|
||||
| Borderless Tables for layout | Both renderers handle well |
|
||||
| `ShadingType.CLEAR` with fill color | Consistent |
|
||||
| `rule: "exact"` on single-level TableRow | Works in both (avoid with nested Tables) |
|
||||
| Paragraph borders (left, bottom, etc.) | Consistent |
|
||||
| `spacing.before` / `spacing.after` | Consistent |
|
||||
| Standard fonts (SimHei, SimSun, YaHei, TNR, Calibri) | Available on both platforms |
|
||||
| `PageBreak` inside Paragraph | Consistent |
|
||||
| Section breaks (`SectionType.NEXT_PAGE`) | Consistent |
|
||||
|
||||
### Mandatory Compatibility Checks (Post-Generation)
|
||||
|
||||
Add to quality self-check:
|
||||
- [ ] No `ShadingType.SOLID` anywhere (search codebase)
|
||||
- [ ] No `verticalAlign: "center"` or `"bottom"` in exact-height rows
|
||||
- [ ] No tab-stop alignment for party info or data alignment (use Tables)
|
||||
- [ ] Covers use the 16838 outer wrapper architecture (R1 pattern) with `spacing.before` for positioning; no `margins.top`/`margins.bottom` in exact-height cells
|
||||
- [ ] **Cover section margin = `{ top: 0, bottom: 0, left: 0, right: 0 }`** — non-zero margins cause wrapper to shrink away from page edges
|
||||
- [ ] **Cover wrapper row has `height: { value: 16838, rule: "exact" }`** — without this, content overflows or leaves whitespace
|
||||
- [ ] **Cover is in a separate section from body content** — cover and body must not share a section
|
||||
- [ ] **Cover wrapper table uses explicit `allNoBorders`** — never rely on default table borders (causes blank page 2 in MS Office)
|
||||
- [ ] **No text-character decorative lines** (`───`, `━━━`, `═══`, `——————`) — use paragraph borders instead
|
||||
- [ ] `characterSpacing` values ≤ 80 throughout
|
||||
- [ ] TOC: follow `references/toc.md` checklist (heading style, TableOfContents element, PageBreak, post-processing script)
|
||||
- [ ] All tables use `WidthType.PERCENTAGE` for column widths (WPS tblGrid bug; if DXA is unavoidable, set `columnWidths` explicitly)
|
||||
|
||||
```js
|
||||
// ✅ Correct — percentage widths, WPS-safe
|
||||
new Table({
|
||||
width: { size: 100, type: WidthType.PERCENTAGE },
|
||||
rows: [new TableRow({ children: [
|
||||
new TableCell({ width: { size: 30, type: WidthType.PERCENTAGE }, children: [...] }),
|
||||
new TableCell({ width: { size: 70, type: WidthType.PERCENTAGE }, children: [...] }),
|
||||
]})],
|
||||
});
|
||||
|
||||
// ❌ WRONG — DXA widths cause WPS tblGrid mismatch (all gridCol=100)
|
||||
new TableCell({ width: { size: 3000, type: WidthType.DXA }, ... })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Universal Prohibitions
|
||||
|
||||
These apply to ALL scenes. Scene files may add scene-specific prohibitions.
|
||||
|
||||
1. **No outlines-only** — always produce a complete, finished document
|
||||
2. **No chat-style output** — the document must not read like a conversation or explanation
|
||||
3. **No fake TOC / page numbers / headers** — use proper docx-js structures
|
||||
4. **No excessive blank lines** to pad layout
|
||||
5. **No dirty formatting** — no stray annotations, template fragments, broken hyperlinks, garbled markers
|
||||
6. **No sloppy placeholders** — "TBD", "omitted", "略", "to be refined" are forbidden; use proper `【】` placeholders
|
||||
7. **No fabricated data** — do not invent statistics, citations, legal references, or facts to appear professional
|
||||
8. **No inconsistent heading/numbering** — one numbering system per document, no level-skipping
|
||||
9. **No Markdown artifacts** — no `#`, `**`, `-` list markers, `>` blockquotes, and **no Markdown table syntax** (`| col1 | col2 |`, `|---|---|`) in the final docx. Any tabular data MUST be rendered as a proper docx `Table` object — never as plain-text pipe-delimited lines. This applies to ALL scenes including exam paper data tables, report statistics, and academic result tables.
|
||||
10. **No bullet-list documents** — body text must be proper paragraphs, not endless bullet points
|
||||
|
||||
## Letter / Correspondence Format (Universal)
|
||||
|
||||
When generating any letter-style document (invitation letter, thank-you letter, cover letter, recommendation letter, English essay in letter format, etc.), the following layout rules apply regardless of scene:
|
||||
|
||||
1. **Complimentary close and sender name MUST be right-aligned** — e.g., "Yours sincerely,", "Best regards,", "Yours,", and the sender name below it must use `alignment: AlignmentType.RIGHT`
|
||||
2. **Date** — if placed at the top of the letter, right-aligned; if at the bottom, right-aligned with the closing
|
||||
3. **Salutation** ("Dear Mr. Smith," / "Dear Mike,") — left-aligned, followed by a blank line or `spacing.after`
|
||||
4. **Body paragraphs** — left-aligned (English) or justified (CJK), with appropriate `spacing.after` between paragraphs
|
||||
|
||||
```js
|
||||
// ✅ Correct — closing and sender right-aligned
|
||||
new Paragraph({ alignment: AlignmentType.RIGHT, spacing: { before: 400 },
|
||||
children: [new TextRun({ text: "Yours sincerely,", size: 24 })] }),
|
||||
new Paragraph({ alignment: AlignmentType.RIGHT,
|
||||
children: [new TextRun({ text: "Li Hua", size: 24 })] }),
|
||||
|
||||
// ❌ WRONG — closing left-aligned (default)
|
||||
new Paragraph({
|
||||
children: [new TextRun({ text: "Yours sincerely," })] }),
|
||||
```
|
||||
|
||||
## Quality Self-Check (Universal)
|
||||
|
||||
→ See **SKILL.md § Post-Generation — Two-Layer Verification** for the complete checklist.
|
||||
|
||||
Scene files add scene-specific checks on top of that universal checklist.
|
||||
|
||||
## Execution Priority
|
||||
|
||||
When rules conflict, follow this precedence (highest first):
|
||||
|
||||
1. **User-provided template or explicit instructions** — always override defaults
|
||||
2. **Scene-specific rules** — override common rules and design-system defaults
|
||||
3. **Common rules** (this file) — override design-system aesthetic defaults
|
||||
4. **Design-system defaults** — baseline aesthetics
|
||||
|
||||
## Cover Recipes
|
||||
|
||||
See `references/design-system.md` for the 7 validated cover recipes (R1–R7) and 14 color palettes.
|
||||
|
||||
Cover recipe selection: `selectCoverRecipe(docType, industry, titleLength)` — defined in `references/design-system.md` (authoritative source).
|
||||
|
||||
---
|
||||
|
||||
## Cover Title Layout Rules (Mandatory)
|
||||
|
||||
These rules apply to ALL cover recipes (R1–R7). They prevent the most common cover quality issues: title overflow, content spilling to page 2, and mid-word line breaks.
|
||||
|
||||
### Rule 1: Always use `calcTitleLayout()`
|
||||
|
||||
Every cover MUST call `calcTitleLayout(title, availableWidth)` from `design-system.md` to determine:
|
||||
- **Font size** (dynamically calculated, never hardcoded above 40pt)
|
||||
- **Line breaks** (semantically split, never mid-word)
|
||||
|
||||
**Forbidden:** Passing the full title as a single long TextRun and letting Word auto-wrap. This causes uncontrolled line breaks at arbitrary character positions.
|
||||
|
||||
### Rule 2: No single-character orphan lines
|
||||
|
||||
If the last line of a title contains only 1–2 characters, merge it into the previous line. The `splitTitleLines()` function handles this automatically.
|
||||
|
||||
### Rule 3: No mid-word breaks for CJK text
|
||||
|
||||
Line breaks must occur at semantic boundaries: after particles (e.g., de/yu/he/ji/zhi), punctuation, connectors, spaces, or underscores. Never split a compound term (e.g., a 4-character term like a management specification must not be split into 3+1 characters).
|
||||
|
||||
For mixed Chinese+English titles (e.g., "基于Transformer架构的..."), use `estimateTextWidth()` instead of character count for line break calculation. Chinese characters are ~2× wider than English characters at the same font size.
|
||||
|
||||
### Rule 4: Maximum 3 title lines on cover
|
||||
|
||||
Cover titles must not exceed 3 lines. If the title is too long, reduce font size (down to minimum 24pt) before adding more lines. If it still exceeds 3 lines at 24pt, force 3 lines with longer line lengths.
|
||||
|
||||
### Rule 5: Always use `calcCoverSpacing()` for whitespace
|
||||
|
||||
Spacing values (`spacing.before`) in cover elements must be dynamically calculated, not hardcoded. Fixed values like `before: 4500` assume a specific title length and will cause overflow with longer titles.
|
||||
|
||||
### Rule 6: Cover height budget validation
|
||||
|
||||
Before generating, verify that total content height stays within 15638 twips (16838 page height minus 1200 twips safety margin — MS Office renders large fonts taller than calculated). Each recipe in `design-system.md` includes height budget annotations — verify during generation.
|
||||
|
||||
### Rule 7: R5 meta info table (academic covers)
|
||||
|
||||
Academic cover meta info must use a 2-column table with **percentage widths only** (NOT DXA — WPS breaks with DXA widths):
|
||||
- **Table width:** adaptive 55–75% of page, calculated by `calcR5MetaLayout()` in `design-system.md`. Table is centered via `alignment: CENTER`.
|
||||
- **Label column:** adaptive 25–45% of table width, **LEFT aligned**, plain text label + ":". NO full-width space padding, NO right-alignment, NO distributed alignment.
|
||||
- **Value column:** remaining percentage, **LEFT aligned**, `bottom border single sz=4` = fixed-length underline (same length for all rows regardless of value text length).
|
||||
- **Label column borders:** none (NO bottom border on label cells).
|
||||
- ⚠️ Do NOT use DXA widths, full-width space padding (`\u3000`), spacer columns, or tab stops — these render inconsistently between MS Office and WPS.
|
||||
|
||||
### Rule 8: Large font paragraphs must set explicit line spacing
|
||||
|
||||
When a paragraph uses a font size larger than the document body text (e.g., cover titles at 36pt+), it **MUST** set explicit `spacing.line` to prevent clipping. Without it, the paragraph inherits the document/style default line spacing (often 560 twips for body text), which is smaller than the font height → the top of characters gets clipped.
|
||||
|
||||
**Formula:** `spacing.line = Math.ceil(fontPt * 23)` with `lineRule: "atLeast"`
|
||||
|
||||
**Example:** A 36pt title needs `spacing: { line: 828, lineRule: "atLeast" }`. Without this, the inherited `line=560` clips the top 160 twips of the text.
|
||||
|
||||
This applies to ALL large-font paragraphs (cover titles, chapter headings, decorative text), not just covers.
|
||||
|
||||
### Rule 9: Every TextRun on a colored background MUST set explicit `color`
|
||||
|
||||
⚠️ **CRITICAL:** When a TextRun is inside a cell/area with a dark or colored background (shading), it **MUST** explicitly set the `color` property. Omitting `color` defaults to black (`#000000`), which is invisible on dark backgrounds.
|
||||
|
||||
**Common mistake:** Subtitle or meta text on R1/R2/R4 dark cover blocks without `color` → appears as invisible black text on dark bg.
|
||||
|
||||
**Rule:** For any TextRun inside a shaded cell:
|
||||
- Use `P.cover.titleColor` for title text
|
||||
- Use `P.cover.subtitleColor` for subtitle text
|
||||
- Use `P.cover.metaColor` for meta info text
|
||||
- Use `P.cover.footerColor` for footer text
|
||||
- **NEVER** rely on default color when background is not white
|
||||
|
||||
### Rule 10: Page number API nesting and 3-section numbering
|
||||
|
||||
⚠️ **CRITICAL:** Page number settings MUST be nested inside `page.pageNumbers`:
|
||||
|
||||
```js
|
||||
// ❌ WRONG — docx-js ignores top-level pageNumberStart/pageNumberFormatType
|
||||
properties: { pageNumberStart: 1, pageNumberFormatType: NumberFormat.DECIMAL }
|
||||
|
||||
// ✅ CORRECT
|
||||
properties: { page: { pageNumbers: { start: 1, formatType: NumberFormat.DECIMAL } } }
|
||||
```
|
||||
|
||||
**Standard page numbering (5-zone convention):**
|
||||
|
||||
All multi-section documents MUST follow this five-zone page numbering scheme unless the user explicitly requests otherwise.
|
||||
|
||||
| Zone | Section | pageNumbers | Footer instrText | Notes |
|
||||
|------|---------|-------------|-----------------|-------|
|
||||
| 1. Cover | Title page | None (no footer) | — | Always logical page 1, but number is **hidden** |
|
||||
| 2. Front matter | Abstract, TOC, Preface | `{ start: 1, formatType: UPPER_ROMAN }` | `PAGE \* ROMAN \* MERGEFORMAT` | Separate Roman numeral sequence (i, ii, iii…) |
|
||||
| 3. Body | Main content | `{ start: 1, formatType: DECIMAL }` | `PAGE \* arabic \* MERGEFORMAT` | **Resets to 1** |
|
||||
| 4. Appendix | Appendices (A, B, C…) | Continues body (no reset) | Same as body | No section break needed unless different headers required |
|
||||
| 5. References | Bibliography | Continues body (no reset) | Same as body | If body ends on p.42, references continue from p.43 |
|
||||
|
||||
**Key rules:**
|
||||
0. **NEVER use "Page X of Y" denominator format.** Footer must show only the current page number (e.g., `1`, `2`, `iii`). Do NOT display total page count. No `Page 3 of 12`, no `3 / 12`, no `第3页/共12页`. Just the bare number. `PageNumber.TOTAL_PAGES` / `NUMPAGES` is **FORBIDDEN** in footers.
|
||||
1. **Cover is always page 1 internally** but the page number is never displayed. Suppress footer in cover section.
|
||||
2. **Front matter uses independent Roman numerals** starting at `i`. This sequence is separate from the body.
|
||||
3. **Body resets to Arabic 1.** The first page of main content is always page `1`.
|
||||
4. **Appendix and references continue the body sequence.** No reset between body → appendix → references.
|
||||
5. **Documents without front matter** skip zone 2 (cover hidden, body starts at Arabic 1).
|
||||
6. **Documents without cover** start body (or front matter) at page 1 directly.
|
||||
7. **Short documents (≤3 pages):** simple Arabic 1, 2, 3 throughout, no cover/frontmatter distinction.
|
||||
8. **Single-page documents** (certificates, letters): no page numbering at all.
|
||||
|
||||
**3-section docx-js implementation (for documents with TOC):**
|
||||
|
||||
At minimum, implement zones 1–3 as separate docx sections:
|
||||
|
||||
```js
|
||||
// Section 1: Cover — no page number
|
||||
properties: { page: { /* no pageNumbers */ } }
|
||||
// No footer children, or empty footer
|
||||
|
||||
// Section 2: Front matter — Roman numerals
|
||||
properties: { page: { pageNumbers: { start: 1, formatType: NumberFormat.UPPER_ROMAN } } }
|
||||
// Footer: PAGE \* ROMAN \* MERGEFORMAT
|
||||
|
||||
// Section 3: Body — Arabic, reset to 1
|
||||
properties: { page: { pageNumbers: { start: 1, formatType: NumberFormat.DECIMAL } } }
|
||||
// Footer: PAGE \* arabic \* MERGEFORMAT
|
||||
|
||||
// Appendix and References: same section as body (continues numbering)
|
||||
// Only create a new section if different header/footer content is needed
|
||||
```
|
||||
|
||||
**Post-processing required** (WPS compatibility):
|
||||
1. Remove empty `<w:pgNumType/>` from cover section XML
|
||||
2. Patch footer instrText: replace bare `PAGE` with format-specific `PAGE \* ROMAN` or `PAGE \* arabic`
|
||||
|
||||
See `toc.md` § Page Number API for full details.
|
||||
Reference in New Issue
Block a user