import { Paragraph } from "./paragraph"; import { Insert } from "./insert"; import { Delete } from "./delete"; import { DeleteText } from "./delete-text"; import { Table } from "./table"; import { TableCell } from "./table-cell"; import { BorderType } from "./table-cell-border"; import { Run } from "./run"; import { Text } from "./text"; import { Tab } from "./tab"; import { Break } from "./break"; import { Comment } from "./comment"; import { CommentEnd } from "./comment-end"; import { AbstractNumbering } from "./abstract-numbering"; import { Numbering } from "./numbering"; import { BookmarkStart } from "./bookmark-start"; import { BookmarkEnd } from "./bookmark-end"; import { Settings } from "./settings"; import { DocxJSON } from "./json"; import * as wasm from "./pkg"; const convertBorderType = (t: BorderType) => { switch (t) { case "nil": return wasm.BorderType.Nil; case "none": return wasm.BorderType.None; case "single": return wasm.BorderType.Single; case "thick": return wasm.BorderType.Thick; case "double": return wasm.BorderType.Double; case "dotted": return wasm.BorderType.Dotted; case "dashed": return wasm.BorderType.Dashed; case "dotDash": return wasm.BorderType.DotDash; case "dotDotDash": return wasm.BorderType.DotDotDash; case "triple": return wasm.BorderType.Triple; default: return wasm.BorderType.Single; } }; export class Docx { children: (Paragraph | Table)[] = []; hasNumberings = false; abstractNumberings: AbstractNumbering[] = []; numberings: Numbering[] = []; settings: Settings = new Settings(); addParagraph(p: Paragraph) { if (p.hasNumberings) { this.hasNumberings = true; } this.children.push(p); return this; } addTable(t: Table) { if (t.hasNumberings) { this.hasNumberings = true; } this.children.push(t); return this; } addAbstractNumbering(num: AbstractNumbering) { this.abstractNumberings.push(num); return this; } addNumbering(num: Numbering) { this.numberings.push(num); return this; } docId(id: string) { this.settings.docId(id); return this; } buildRun(r: Run) { let run = wasm.createRun(); r.children.forEach((child) => { if (child instanceof Text) { run = run.add_text(child.text); } else if (child instanceof DeleteText) { run = run.add_delete_text(child.text); } else if (child instanceof Tab) { run = run.add_tab(); } else if (child instanceof Break) { if (child.type === "column") { run = run.add_break(wasm.BreakType.Column); } else if (child.type === "page") { run = run.add_break(wasm.BreakType.Page); } else if (child.type === "textWrapping") { run = run.add_break(wasm.BreakType.TextWrapping); } } }); if (typeof r.property.size !== "undefined") { run = run.size(r.property.size); } if (r.property.color) { run = run.color(r.property.color); } if (r.property.highlight) { run = run.highlight(r.property.highlight); } if (r.property.bold) { run = run.bold(); } if (r.property.italic) { run = run.italic(); } if (r.property.underline) { run = run.underline(r.property.underline); } if (r.property.vanish) { run = run.vanish(); } let f = wasm.createRunFonts(); if (r.property.fonts?._ascii) { f = f.ascii(r.property.fonts._ascii); } if (r.property.fonts?._hiAnsi) { f = f.hi_ansi(r.property.fonts._hiAnsi); } if (r.property.fonts?._cs) { f = f.cs(r.property.fonts._cs); } if (r.property.fonts?._eastAsia) { f = f.east_asia(r.property.fonts._eastAsia); } run = run.fonts(f); return run; } buildInsert(i: Insert) { const run = this.buildRun(i.run); let insert = wasm.createInsert(run); if (i._author) { insert = insert.author(i._author); } if (i._date) { insert = insert.date(i._date); } return insert; } buildDelete(d: Delete) { const run = this.buildRun(d.run); let del = wasm.createDelete(run); if (d._author) { del = del.author(d._author); } if (d._date) { del = del.date(d._date); } return del; } buildComment(c: Comment) { let comment = wasm.createComment(c.id); if (c._paragraph) { comment = comment.paragraph(this.buildParagraph(c._paragraph)); } if (c._author) { comment = comment.author(c._author); } if (c._date) { comment = comment.date(c._date); } if (c._parentCommentId) { comment = comment.parent_comment_id(c._parentCommentId); } return comment; } buildParagraph(p: Paragraph) { let paragraph = wasm.createParagraph(); p.children.forEach((child) => { if (child instanceof Run) { const run = this.buildRun(child); paragraph = paragraph.add_run(run); } else if (child instanceof Insert) { const insert = this.buildInsert(child); paragraph = paragraph.add_insert(insert); } else if (child instanceof Delete) { const del = this.buildDelete(child); paragraph = paragraph.add_delete(del); } else if (child instanceof BookmarkStart) { paragraph = paragraph.add_bookmark_start(child.id, child.name); } else if (child instanceof BookmarkEnd) { paragraph = paragraph.add_bookmark_end(child.id); } else if (child instanceof Comment) { const comment = this.buildComment(child); paragraph = paragraph.add_comment_start(comment); } else if (child instanceof CommentEnd) { paragraph = paragraph.add_comment_end(child.id); } }); switch (p.property.align) { case "center": { paragraph = paragraph.align(wasm.AlignmentType.Center); break; } case "right": { paragraph = paragraph.align(wasm.AlignmentType.Right); break; } case "justified": { paragraph = paragraph.align(wasm.AlignmentType.Justified); break; } case "left": { paragraph = paragraph.align(wasm.AlignmentType.Left); break; } case "distribute": { paragraph = paragraph.align(wasm.AlignmentType.Distribute); break; } case "both": { paragraph = paragraph.align(wasm.AlignmentType.Both); break; } case "end": { paragraph = paragraph.align(wasm.AlignmentType.End); break; } } if (typeof p.property.indent !== "undefined") { const { indent } = p.property; let kind; switch (p.property.indent.specialIndentKind) { case "firstLine": { kind = wasm.SpecialIndentKind.FirstLine; break; } case "hanging": { kind = wasm.SpecialIndentKind.Hanging; break; } } paragraph = paragraph.indent(indent.left, kind, indent.specialIndentSize); } if (typeof p.property.numbering !== "undefined") { const { numbering } = p.property; paragraph = paragraph.numbering(numbering.id, numbering.level); } if (typeof p.property.styleId !== "undefined") { paragraph = paragraph.style(p.property.styleId); } if (p.property.runProperty.bold) { paragraph = paragraph.bold(); } if (p.property.runProperty.bold) { paragraph = paragraph.bold(); } if (p.property.runProperty.italic) { paragraph = paragraph.italic(); } if (p.property.runProperty.size) { paragraph = paragraph.size(p.property.runProperty.size); } if (p.property.runProperty.fonts) { let f = wasm.createRunFonts(); if (p.property.runProperty.fonts._ascii) { f = f.ascii(p.property.runProperty.fonts._ascii); } if (p.property.runProperty.fonts._hiAnsi) { f = f.hi_ansi(p.property.runProperty.fonts._hiAnsi); } if (p.property.runProperty.fonts._cs) { f = f.cs(p.property.runProperty.fonts._cs); } if (p.property.runProperty.fonts._eastAsia) { f = f.east_asia(p.property.runProperty.fonts._eastAsia); } paragraph = paragraph.fonts(f); } return paragraph; } buildTable(t: Table) { let table = wasm.createTable(); t.rows.forEach((r) => { let row = wasm.createTableRow(); r.cells.forEach((c) => { const cell = this.buildCell(c); row = row.add_cell(cell); }); table = table.add_row(row); }); table = table.set_grid(new Uint32Array(t.grid)); table = table.indent(t.property.indent || 0); switch (t.property.align) { case "center": { table = table.align(wasm.TableAlignmentType.Center); break; } case "right": { table = table.align(wasm.TableAlignmentType.Right); break; } case "left": { table = table.align(wasm.TableAlignmentType.Left); break; } } return table; } buildCell(c: TableCell) { let cell = wasm.createTableCell(); c.children.forEach((p) => { const paragraph = this.buildParagraph(p); cell = cell.add_paragraph(paragraph); }); if (c.property.verticalMerge === "continue") { cell = cell.vertical_merge(wasm.VMergeType.Continue); } else if (c.property.verticalMerge === "restart") { cell = cell.vertical_merge(wasm.VMergeType.Restart); } switch (c.property.verticalAlign) { case "top": { cell = cell.vertical_align(wasm.VAlignType.Top); break; } case "center": { cell = cell.vertical_align(wasm.VAlignType.Center); break; } case "bottom": { cell = cell.vertical_align(wasm.VAlignType.Bottom); break; } } if (typeof c.property.gridSpan !== "undefined") { cell = cell.grid_span(c.property.gridSpan); } if (typeof c.property.width !== "undefined") { cell = cell.width(c.property.width); } if (typeof c.property.borders !== "undefined") { if (c.property.borders.top) { const border = wasm .createTableCellBorder(wasm.BorderPosition.Top) .size(c.property.borders.top._size) .color(c.property.borders.top._color) .border_type(convertBorderType(c.property.borders.top._border_type)); cell = cell.set_border(border); } if (c.property.borders.right) { const border = wasm .createTableCellBorder(wasm.BorderPosition.Right) .size(c.property.borders.right._size) .color(c.property.borders.right._color) .border_type( convertBorderType(c.property.borders.right._border_type) ); cell = cell.set_border(border); } if (c.property.borders.bottom) { const border = wasm .createTableCellBorder(wasm.BorderPosition.Bottom) .size(c.property.borders.bottom._size) .color(c.property.borders.bottom._color) .border_type( convertBorderType(c.property.borders.bottom._border_type) ); cell = cell.set_border(border); } if (c.property.borders.left) { const border = wasm .createTableCellBorder(wasm.BorderPosition.Left) .size(c.property.borders.left._size) .color(c.property.borders.left._color) .border_type(convertBorderType(c.property.borders.left._border_type)); cell = cell.set_border(border); } if (c.property.borders.insideH) { const border = wasm .createTableCellBorder(wasm.BorderPosition.InsideH) .size(c.property.borders.insideH._size) .color(c.property.borders.insideH._color) .border_type( convertBorderType(c.property.borders.insideH._border_type) ); cell = cell.set_border(border); } if (c.property.borders.insideV) { const border = wasm .createTableCellBorder(wasm.BorderPosition.InsideV) .size(c.property.borders.insideV._size) .color(c.property.borders.insideV._color) .border_type( convertBorderType(c.property.borders.insideV._border_type) ); cell = cell.set_border(border); } } return cell; } build() { let docx = wasm.createDocx(); this.children.forEach((child) => { if (child instanceof Paragraph) { let p = this.buildParagraph(child); docx = docx.add_paragraph(p); } else if (child instanceof Table) { let t = this.buildTable(child); docx = docx.add_table(t); } }); this.abstractNumberings.forEach((n) => { let num = wasm.createAbstractNumbering(n.id); n.levels.forEach((l) => { let level = wasm.createLevel(l.id, l.start, l.format, l.text, l.jc); if (l.levelSuffix === "nothing") { level = level.suffix(wasm.LevelSuffixType.Nothing); } else if (l.levelSuffix === "space") { level = level.suffix(wasm.LevelSuffixType.Space); } else { level = level.suffix(wasm.LevelSuffixType.Tab); } if (l.paragraphProperty.indent) { let kind; if (l.paragraphProperty.indent.specialIndentKind === "firstLine") { kind = wasm.SpecialIndentKind.FirstLine; } else if ( l.paragraphProperty.indent.specialIndentKind === "hanging" ) { kind = wasm.SpecialIndentKind.Hanging; } level = level.indent( l.paragraphProperty.indent.left, kind, l.paragraphProperty.indent.specialIndentSize ); } num = num.add_level(level); }); docx = docx.add_abstract_numbering(num); }); this.numberings.forEach((n) => { let num = wasm.createNumbering(n.id, n.abstractNumId); n.overrides.forEach((o) => { let levelOverride = wasm.createLevelOverride(o.level); if (o.startOverride !== null) { levelOverride = levelOverride.start(o.startOverride); } num = num.add_override(levelOverride); }); docx = docx.add_numbering(num); }); if (this.settings._docId) { docx = docx.doc_id(this.settings._docId); } const buf = docx.build(this.hasNumberings); docx.free(); return buf; } } export const readDocx = (buf: Uint8Array) => { return JSON.parse(wasm.readDocx(buf)) as DocxJSON; }; export * from "./paragraph"; export * from "./insert"; export * from "./delete"; export * from "./table"; export * from "./table-cell"; export * from "./table-cell-border"; export * from "./table-cell-borders"; export * from "./table-row"; export * from "./run"; export * from "./text"; export * from "./comment"; export * from "./comment-end"; export * from "./numbering"; export * from "./abstract-numbering"; export * from "./bookmark-start"; export * from "./bookmark-end"; export * from "./break"; export * from "./delete-text"; export * from "./level"; export * from "./tab"; export * from "./json";