Add style properties (#530)

* fix: support run style

* fix: table style

* fix: support run style in js

* fix: support paragraph style

* fix

* fix: package

* fix

* rc15

* fix

* fix

* fix

* fix

* fix: test

* fix
main
bokuweb 2022-09-09 11:10:05 +09:00 committed by GitHub
parent cf31b7ad0a
commit 2b6344f31b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 909 additions and 291 deletions

View File

@ -0,0 +1,40 @@
use docx_rs::*;
pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./output/examples/style.docx");
let file = std::fs::File::create(&path).unwrap();
let p1 = Paragraph::new()
.add_run(Run::new().add_text("Hello").style("Run1"))
.add_run(Run::new().add_text(" World"))
.style("Heading1")
.page_break_before(true);
let table =
Table::new(vec![TableRow::new(vec![TableCell::new().add_paragraph(
Paragraph::new().add_run(Run::new().add_text("Hello")),
)])])
.style("Table1");
let style1 = Style::new("Heading1", StyleType::Paragraph)
.name("Heading 1")
.align(AlignmentType::Center);
let style2 = Style::new("Run1", StyleType::Character)
.name("Run test")
.bold();
let style3 = Style::new("Table1", StyleType::Table)
.name("Table test")
.table_align(TableAlignmentType::Center);
Docx::new()
.add_style(style1)
.add_style(style2)
.add_style(style3)
.add_paragraph(p1)
.add_table(table)
.build()
.pack(file)?;
Ok(())
}

View File

@ -4,40 +4,9 @@ pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./table.docx");
let file = std::fs::File::create(&path).unwrap();
let table = Table::new(vec![
TableRow::new(vec![
TableCell::new()
.add_paragraph(Paragraph::new())
.grid_span(2)
.shading(Shading::new().fill("FF0000")),
TableCell::new()
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")))
.vertical_align(VAlignType::Center)
.vertical_merge(VMergeType::Restart)
.text_direction(TextDirectionType::TbRlV),
]),
TableRow::new(vec![
TableCell::new()
.add_paragraph(Paragraph::new())
.vertical_merge(VMergeType::Restart),
TableCell::new().add_paragraph(Paragraph::new()),
TableCell::new()
.add_paragraph(Paragraph::new())
.vertical_merge(VMergeType::Continue),
]),
TableRow::new(vec![
TableCell::new()
.add_paragraph(Paragraph::new())
.vertical_merge(VMergeType::Continue),
TableCell::new().add_paragraph(Paragraph::new()),
TableCell::new()
.add_paragraph(Paragraph::new())
.vertical_merge(VMergeType::Continue),
]),
])
.set_grid(vec![2000, 2000, 2000])
.layout(TableLayoutType::Fixed)
.indent(1000);
let table = Table::new(vec![TableRow::new(vec![
TableCell::new().add_paragraph(Paragraph::new())
])]);
Docx::new().add_table(table).build().pack(file)?;
Ok(())
}

View File

@ -163,6 +163,7 @@ impl BuildXML for RunProperty {
.add_optional_child(&self.del)
.add_optional_child(&self.vert_align)
.add_optional_child(&self.character_spacing)
.add_optional_child(&self.style)
.close()
.build()
}

View File

@ -100,6 +100,16 @@ impl Style {
self
}
pub fn text_border(mut self, b: TextBorder) -> Self {
self.run_property = self.run_property.text_border(b);
self
}
pub fn fonts(mut self, f: RunFonts) -> Self {
self.run_property = self.run_property.fonts(f);
self
}
pub fn align(mut self, alignment_type: AlignmentType) -> Self {
self.paragraph_property = self.paragraph_property.align(alignment_type);
self
@ -138,6 +148,56 @@ impl Style {
self
}
pub fn table_indent(mut self, v: i32) -> Self {
self.table_property = self.table_property.indent(v);
self
}
pub fn table_align(mut self, v: TableAlignmentType) -> Self {
self.table_property = self.table_property.align(v);
self
}
pub fn style(mut self, s: impl Into<String>) -> Self {
self.table_property = self.table_property.style(s);
self
}
pub fn layout(mut self, t: TableLayoutType) -> Self {
self.table_property = self.table_property.layout(t);
self
}
pub fn width(mut self, w: usize, t: WidthType) -> Self {
self.table_property = self.table_property.width(w, t);
self
}
pub fn margins(mut self, margins: TableCellMargins) -> Self {
self.table_property = self.table_property.set_margins(margins);
self
}
pub fn set_borders(mut self, borders: TableBorders) -> Self {
self.table_property = self.table_property.set_borders(borders);
self
}
pub fn set_border(mut self, border: TableBorder) -> Self {
self.table_property = self.table_property.set_border(border);
self
}
pub fn clear_border(mut self, position: TableBorderPosition) -> Self {
self.table_property = self.table_property.clear_border(position);
self
}
pub fn clear_all_border(mut self) -> Self {
self.table_property = self.table_property.clear_all_border();
self
}
pub fn table_cell_property(mut self, p: TableCellProperty) -> Self {
self.table_cell_property = p;
self
@ -153,11 +213,13 @@ impl BuildXML for Style {
.add_child(&self.name)
.add_child(&self.run_property)
.add_child(&self.paragraph_property);
if self.style_type == StyleType::Table {
b = b
.add_child(&self.table_cell_property)
.add_child(&self.table_property);
}
if let Some(ref based_on) = self.based_on {
b = b.add_child(based_on)
}

View File

@ -1,14 +1,13 @@
import { Paragraph } from "./paragraph";
import { ParagraphProperty } from "./paragraph-property";
import { ParagraphProperty, setParagraphProperty } from "./paragraph-property";
import { Insert } from "./insert";
import { Delete } from "./delete";
import { convertHyperlinkType, Hyperlink } from "./hyperlink";
import { DeleteText } from "./delete-text";
import { Table } from "./table";
import { setTableProperty, Table } from "./table";
import { TableOfContents } from "./table-of-contents";
import { TableCell, toTextDirectionWasmType } from "./table-cell";
import { BorderType } from "./border";
import { Run, RunFonts } from "./run";
import { convertBorderType, Run, RunFonts, setRunProperty } from "./run";
import { Text } from "./text";
import { Tab } from "./tab";
import { Break } from "./break";
@ -37,52 +36,6 @@ import { DocGridType, DocxJSON } from "./json";
import * as wasm from "./pkg";
import { Level } from "./level";
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;
}
};
const convertWidthType = (t: string) => {
switch (t) {
case "nil":
case "Nil":
return wasm.WidthType.Nil;
case "Pct":
case "pct":
return wasm.WidthType.Pct;
case "DXA":
case "dxa":
return wasm.WidthType.Dxa;
case "Auto":
case "auto":
return wasm.WidthType.Auto;
default:
return wasm.WidthType.Dxa;
}
};
export class Docx {
children: (
| Paragraph
@ -315,63 +268,7 @@ export class Docx {
}
});
if (r.property.style) {
run = run.style(r.property.style);
}
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.vertAlign) {
if (r.property.vertAlign === "superscript") {
run = run.vert_align(wasm.VertAlignType.SuperScript);
} else if (r.property.vertAlign === "subscript") {
run = run.vert_align(wasm.VertAlignType.SubScript);
}
}
if (r.property.bold) {
run = run.bold();
}
if (r.property.italic) {
run = run.italic();
}
if (r.property.strike) {
run = run.strike();
}
if (r.property.underline) {
run = run.underline(r.property.underline);
}
if (r.property.vanish) {
run = run.vanish();
}
if (r.property.spacing != null) {
run = run.spacing(r.property.spacing);
}
if (r.property.textBorder) {
const { borderType, color, space, size } = r.property.textBorder;
run = run.text_border(convertBorderType(borderType), size, space, color);
}
if (r.property.fonts) {
const fonts = r.property.fonts.buildWasmObject();
run = run.fonts(fonts);
}
run = setRunProperty(run, r.property) as wasm.Run;
return run;
}
@ -521,81 +418,12 @@ export class Docx {
}
});
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);
}
paragraph = setParagraphProperty(paragraph, p.property);
if (typeof p.property.styleId !== "undefined") {
paragraph = paragraph.style(p.property.styleId);
}
if (p.property.runProperty.bold) {
paragraph = paragraph.bold();
}
if (typeof p.property.lineSpacing !== "undefined") {
const spacing = this.buildLineSpacing(p.property);
if (spacing) {
paragraph = paragraph.line_spacing(spacing);
}
}
if (p.property.runProperty.italic) {
paragraph = paragraph.italic();
}
if (p.property.runProperty.size) {
paragraph = paragraph.size(p.property.runProperty.size);
}
if (p.property.runProperty.del) {
paragraph = paragraph.delete(
p.property.runProperty.del.author,
@ -610,39 +438,6 @@ export class Docx {
);
}
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);
}
if (p.property.keepLines) {
paragraph = paragraph.keep_lines(true);
}
if (p.property.keepNext) {
paragraph = paragraph.keep_next(true);
}
if (p.property.pageBreakBefore) {
paragraph = paragraph.page_break_before(true);
}
if (p.property.widowControl) {
paragraph = paragraph.widow_control(true);
}
if (p.property.paragraphPropertyChange) {
let change = wasm.createParagraphPropertyChange();
change = change
@ -701,43 +496,14 @@ export class Docx {
}
table = table.add_row(row);
});
table = table.set_grid(new Uint32Array(t.grid));
table = table.indent(t.property.indent || 0);
if (t.property.cellMargins) {
const { top, right, bottom, left } = t.property.cellMargins;
table = table
.cell_margin_top(top.val, convertWidthType(top.type))
.cell_margin_right(right.val, convertWidthType(right.type))
.cell_margin_bottom(bottom.val, convertWidthType(bottom.type))
.cell_margin_left(left.val, convertWidthType(left.type));
if (t.property.styleId) {
table = table.style(t.property.styleId);
}
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;
}
}
switch (t.property.layout) {
case "fixed": {
table = table.layout(wasm.TableLayoutType.Fixed);
break;
}
case "autofit": {
table = table.layout(wasm.TableLayoutType.Autofit);
break;
}
}
table = setTableProperty(table, t.property);
return table;
}

View File

@ -2,11 +2,12 @@ import { RunPropertyJSON } from "./run";
import { ParagraphPropertyJSON } from "./paragraph";
import { TablePropertyJSON } from "./table";
import { TableCellPropertyJSON } from "..";
import { StyleType } from "../style";
export type StyleJSON = {
styleId: string;
name: string;
styleType: string;
styleType: StyleType;
runProperty: RunPropertyJSON;
paragraphProperty: ParagraphPropertyJSON;
tableProperty: TablePropertyJSON;

View File

@ -1,5 +1,7 @@
import { RunProperty, createDefaultRunProperty } from "./run";
import * as wasm from "./pkg";
export type AlignmentType =
| "center"
| "left"
@ -78,6 +80,37 @@ export const createDefaultParagraphProperty = (): ParagraphProperty => {
};
};
export const createParagraphAlignment = (
align?: AlignmentType | undefined
): wasm.AlignmentType | null => {
switch (align) {
case "center": {
return wasm.AlignmentType.Center;
}
case "right": {
return wasm.AlignmentType.Right;
}
case "justified": {
return wasm.AlignmentType.Justified;
}
case "left": {
return wasm.AlignmentType.Left;
}
case "distribute": {
return wasm.AlignmentType.Distribute;
}
case "both": {
return wasm.AlignmentType.Both;
}
case "end": {
return wasm.AlignmentType.End;
}
default: {
return null;
}
}
};
export class ParagraphPropertyChange {
_author: string = "";
_date: string = "";
@ -117,3 +150,135 @@ export class ParagraphPropertyChange {
return this;
}
}
export const buildLineSpacing = (
p: ParagraphProperty
): wasm.LineSpacing | null => {
const { lineSpacing } = p;
if (lineSpacing == null) return null;
let kind;
switch (lineSpacing._lineRule) {
case "atLeast": {
kind = wasm.LineSpacingType.AtLeast;
break;
}
case "auto": {
kind = wasm.LineSpacingType.Auto;
break;
}
case "exact": {
kind = wasm.LineSpacingType.Exact;
break;
}
}
let spacing = wasm.createLineSpacing();
if (lineSpacing._before != null) {
spacing = spacing.before(lineSpacing._before);
}
if (lineSpacing._after != null) {
spacing = spacing.after(lineSpacing._after);
}
if (lineSpacing._beforeLines != null) {
spacing = spacing.before_lines(lineSpacing._beforeLines);
}
if (lineSpacing._afterLines != null) {
spacing = spacing.after_lines(lineSpacing._afterLines);
}
if (lineSpacing._line != null) {
spacing = spacing.line(lineSpacing._line);
}
if (kind != null) {
spacing = spacing.line_rule(kind);
}
return spacing;
};
export const setParagraphProperty = <T extends wasm.Paragraph | wasm.Style>(
target: T,
property: ParagraphProperty
): T => {
const alignment = createParagraphAlignment(property.align);
if (alignment != null) {
target = target.align(alignment) as T;
}
if (typeof property.indent !== "undefined") {
const { indent } = property;
let kind;
switch (property.indent.specialIndentKind) {
case "firstLine": {
kind = wasm.SpecialIndentKind.FirstLine;
break;
}
case "hanging": {
kind = wasm.SpecialIndentKind.Hanging;
break;
}
}
target = target.indent(indent.left, kind, indent.specialIndentSize) as T;
}
if (typeof property.numbering !== "undefined") {
const { numbering } = property;
target = target.numbering(numbering.id, numbering.level) as T;
}
if (property.runProperty.bold) {
target = target.bold() as T;
}
if (typeof property.lineSpacing !== "undefined") {
const spacing = buildLineSpacing(property);
if (spacing) {
target = target.line_spacing(spacing) as T;
}
}
if (property.runProperty.italic) {
target = target.italic() as T;
}
if (property.runProperty.size) {
target = target.size(property.runProperty.size) as T;
}
if (property.runProperty.fonts) {
let f = wasm.createRunFonts();
if (property.runProperty.fonts._ascii) {
f = f.ascii(property.runProperty.fonts._ascii);
}
if (property.runProperty.fonts._hiAnsi) {
f = f.hi_ansi(property.runProperty.fonts._hiAnsi);
}
if (property.runProperty.fonts._cs) {
f = f.cs(property.runProperty.fonts._cs);
}
if (property.runProperty.fonts._eastAsia) {
f = f.east_asia(property.runProperty.fonts._eastAsia);
}
target = target.fonts(f) as T;
}
if (property.keepLines) {
target = target.keep_lines(true) as T;
}
if (property.keepNext) {
target = target.keep_next(true) as T;
}
if (property.pageBreakBefore) {
target = target.page_break_before(true) as T;
}
if (property.widowControl) {
target = target.widow_control(true) as T;
}
return target;
};

View File

@ -46,6 +46,33 @@ export type RunProperty = {
del?: RunPropertyDel;
};
export 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 const createDefaultRunProperty = (): RunProperty => {
return {};
};
@ -254,3 +281,73 @@ export class Run {
return this;
}
}
export const setRunProperty = <T extends wasm.Run | wasm.Style>(
target: T,
property: RunProperty
): T => {
if (property.style && target instanceof wasm.Run) {
target = target.style(property.style) as T;
}
if (typeof property.size !== "undefined") {
target = target.size(property.size) as T;
}
if (property.color) {
target = target.color(property.color) as T;
}
if (property.highlight) {
target = target.highlight(property.highlight) as T;
}
if (property.vertAlign) {
if (property.vertAlign === "superscript") {
target = target.vert_align(wasm.VertAlignType.SuperScript) as T;
} else if (property.vertAlign === "subscript") {
target = target.vert_align(wasm.VertAlignType.SubScript) as T;
}
}
if (property.bold) {
target = target.bold() as T;
}
if (property.italic) {
target = target.italic() as T;
}
if (property.strike) {
target = target.strike() as T;
}
if (property.underline) {
target = target.underline(property.underline) as T;
}
if (property.vanish) {
target = target.vanish() as T;
}
if (property.spacing != null) {
target = target.spacing(property.spacing) as T;
}
if (property.textBorder) {
const { borderType, color, space, size } = property.textBorder;
target = target.text_border(
convertBorderType(borderType),
size,
space,
color
) as T;
}
if (property.fonts) {
const fonts = property.fonts.buildWasmObject();
target = target.fonts(fonts) as T;
}
return target;
};

View File

@ -1,15 +1,31 @@
import * as wasm from "./pkg";
import { createDefaultTableCellMargins, TableProperty } from "./table";
import { RunProperty, createDefaultRunProperty } from "./run";
import { createDefaultParagraphProperty, ParagraphProperty } from "./paragraph-property";
import {
createDefaultTableCellMargins,
setTableProperty,
TableAlignmentType,
TableLayoutType,
TableProperty,
} from "./table";
import {
RunProperty,
createDefaultRunProperty,
VertAlignType,
RunFonts,
setRunProperty,
} from "./run";
import {
AlignmentType,
createDefaultParagraphProperty,
LineSpacing,
ParagraphProperty,
setParagraphProperty,
SpecialIndentKind,
} from "./paragraph-property";
import { BorderType } from "./border";
import { WidthType } from ".";
export type StyleType =
| "paragraph"
| "character"
| "numbering"
| "table"
| "unsupported";
export type StyleType = "paragraph" | "character" | "numbering" | "table";
export class Style {
_styleId: string;
@ -49,16 +65,203 @@ export class Style {
// return this;
// };
// run property
style(style: string) {
this._runProperty = { ...this._runProperty, style };
return this;
}
size(size: number) {
this._runProperty = { ...this._runProperty, size };
return this;
}
color(color: string) {
this._runProperty = { ...this._runProperty, color };
return this;
}
highlight(color: string) {
this._runProperty = { ...this._runProperty, highlight: color };
return this;
}
vertAlign(vertAlign: VertAlignType) {
this._runProperty = { ...this._runProperty, vertAlign };
return this;
}
bold() {
this._runProperty = { ...this._runProperty, bold: true };
return this;
}
strike() {
this._runProperty = { ...this._runProperty, strike: true };
return this;
}
italic() {
this._runProperty = { ...this._runProperty, italic: true };
return this;
}
underline(type: string) {
this._runProperty = { ...this._runProperty, underline: type };
return this;
}
vanish() {
this._runProperty = { ...this._runProperty, vanish: true };
return this;
}
fonts(fonts: RunFonts) {
this._runProperty = { ...this._runProperty, fonts };
return this;
}
spacing(spacing: number) {
this._runProperty = { ...this._runProperty, spacing };
return this;
}
delete(author: string, date: string) {
this._runProperty = { ...this._runProperty, del: { author, date } };
return this;
}
insert(author: string, date: string) {
this._runProperty = { ...this._runProperty, ins: { author, date } };
return this;
}
textBorder(type: BorderType, size: number, space: number, color: string) {
this._runProperty = {
...this._runProperty,
textBorder: {
borderType: type,
size,
space,
color,
},
};
return this;
}
// TODO:
// paragraphProperty = (n: ParagraphProperty) => {
// this._paragraphProperty = n;
// return this;
// };
tableProperty = (n: TableProperty) => {
this._tableProperty = n;
// paragraph property
align(type: AlignmentType) {
this._paragraphProperty.align = type;
return this;
};
}
indent(
left: number,
specialIndentKind?: SpecialIndentKind,
specialIndentSize?: number
) {
this._paragraphProperty.indent = {
left,
specialIndentKind,
specialIndentSize,
};
return this;
}
numbering(id: number, level: number) {
this._paragraphProperty.numbering = { id, level };
return this;
}
lineSpacing(spacing: LineSpacing) {
this._paragraphProperty.lineSpacing = spacing;
return this;
}
keepNext(v: boolean) {
this._paragraphProperty = { ...this._paragraphProperty, keepNext: v };
return this;
}
keepLines(v: boolean) {
this._paragraphProperty = { ...this._paragraphProperty, keepLines: v };
return this;
}
pageBreakBefore(v: boolean) {
this._paragraphProperty = {
...this._paragraphProperty,
pageBreakBefore: v,
};
return this;
}
widowControl(v: boolean) {
this._paragraphProperty = { ...this._paragraphProperty, widowControl: v };
return this;
}
// tableProperty = (n: TableProperty) => {
// this._tableProperty = n;
// return this;
// };
// tableProperty
tableIndent(v: number) {
this._tableProperty.indent = v;
return this;
}
tableAlign(v: TableAlignmentType) {
this._tableProperty.align = v;
return this;
}
layout(l: TableLayoutType) {
this._tableProperty.layout = l;
return this;
}
width(w: number) {
this._tableProperty.width = w;
return this;
}
cellMargins(top: number, right: number, bottom: number, left: number) {
this._tableProperty.cellMargins = {
top: { val: top, type: "dxa" },
left: { val: left, type: "dxa" },
bottom: { val: bottom, type: "dxa" },
right: { val: right, type: "dxa" },
};
return this;
}
cellMarginTop(v: number, t: WidthType) {
this._tableProperty.cellMargins.top = { val: v, type: t };
return this;
}
cellMarginLeft(v: number, t: WidthType) {
this._tableProperty.cellMargins.left = { val: v, type: t };
return this;
}
cellMarginRight(v: number, t: WidthType) {
this._tableProperty.cellMargins.right = { val: v, type: t };
return this;
}
cellMarginBottom(v: number, t: WidthType) {
this._tableProperty.cellMargins.bottom = { val: v, type: t };
return this;
}
buildStyleType = () => {
switch (this._styleType) {
@ -86,6 +289,12 @@ export class Style {
s = s.based_on(this._basedOn);
}
s = setRunProperty(s, this._runProperty);
s = setParagraphProperty(s, this._paragraphProperty);
s = setTableProperty(s, this._tableProperty);
return s;
};
}

View File

@ -1,3 +1,5 @@
import * as wasm from "./pkg";
import { WidthType } from ".";
import { TableRow } from "./table-row";
@ -8,6 +10,7 @@ export type TableProperty = {
indent?: number;
align?: TableAlignmentType;
width?: number;
styleId?: string;
cellMargins: {
top: { val: number; type: WidthType };
left: { val: number; type: WidthType };
@ -42,6 +45,11 @@ export class Table {
return this;
}
style(id: string) {
this.property.styleId = id;
return this;
}
setGrid(grid: number[]) {
this.grid = grid;
return this;
@ -97,3 +105,78 @@ export class Table {
return this;
}
}
export const convertWidthType = (t: string) => {
switch (t) {
case "nil":
case "Nil":
return wasm.WidthType.Nil;
case "Pct":
case "pct":
return wasm.WidthType.Pct;
case "DXA":
case "dxa":
return wasm.WidthType.Dxa;
case "Auto":
case "auto":
return wasm.WidthType.Auto;
default:
return wasm.WidthType.Dxa;
}
};
export const setTableProperty = <T extends wasm.Table | wasm.Style>(
target: T,
property: TableProperty
): T => {
if (target instanceof wasm.Table) {
target = target.indent(property.indent ?? 0) as T;
} else if (target instanceof wasm.Style) {
target = target.table_indent(property.indent ?? 0) as T;
}
if (property.cellMargins) {
const { top, right, bottom, left } = property.cellMargins;
target = target
.cell_margin_top(top.val, convertWidthType(top.type))
.cell_margin_right(right.val, convertWidthType(right.type))
.cell_margin_bottom(bottom.val, convertWidthType(bottom.type))
.cell_margin_left(left.val, convertWidthType(left.type)) as T;
}
const align = ((): wasm.TableAlignmentType | null => {
switch (property.align) {
case "center": {
return wasm.TableAlignmentType.Center;
}
case "right": {
return wasm.TableAlignmentType.Right;
}
case "left": {
return wasm.TableAlignmentType.Left;
}
default:
return null;
}
})();
if (align != null) {
if (target instanceof wasm.Table) {
target = target.align(align) as T;
} else if (target instanceof wasm.Style) {
target = target.table_align(align) as T;
}
}
switch (property.layout) {
case "fixed": {
target = target.layout(wasm.TableLayoutType.Fixed) as T;
break;
}
case "autofit": {
target = target.layout(wasm.TableLayoutType.Autofit) as T;
break;
}
}
return target;
};

View File

@ -1,6 +1,6 @@
{
"name": "docx-wasm",
"version": "0.0.276-rc14",
"version": "0.0.276-rc18",
"main": "dist/node/index.js",
"browser": "dist/web/index.js",
"author": "bokuweb <bokuweb12@gmail.com>",

View File

@ -1,4 +1,5 @@
use super::*;
use docx_rs::{BorderType, TextBorder, VertAlignType, WidthType};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
@ -47,6 +48,11 @@ impl Style {
self
}
pub fn strike(mut self) -> Self {
self.0.run_property = self.0.run_property.strike();
self
}
pub fn underline(mut self, line_type: &str) -> Self {
self.0.run_property = self.0.run_property.underline(line_type);
self
@ -57,6 +63,37 @@ impl Style {
self
}
pub fn fonts(mut self, f: RunFonts) -> Self {
self.0 = self.0.fonts(f.take());
self
}
pub fn spacing(mut self, spacing: i32) -> Self {
self.0.run_property = self.0.run_property.spacing(spacing);
self
}
pub fn vert_align(mut self, a: VertAlignType) -> Self {
self.0.run_property = self.0.run_property.vert_align(a);
self
}
pub fn text_border(
mut self,
border_type: BorderType,
size: usize,
space: usize,
color: &str,
) -> Self {
let border = TextBorder::new()
.border_type(border_type)
.size(size)
.space(space)
.color(color);
self.0.run_property = self.0.run_property.text_border(border);
self
}
pub fn align(mut self, alignment_type: docx_rs::AlignmentType) -> Self {
self.0.paragraph_property = self.0.paragraph_property.align(alignment_type);
self
@ -81,6 +118,39 @@ impl Style {
self
}
// TODO: For now only numbering supported.
pub fn numbering(mut self, id: usize, level: usize) -> Self {
let id = docx_rs::NumberingId::new(id);
let level = docx_rs::IndentLevel::new(level);
self.0.paragraph_property = self.0.paragraph_property.numbering(id, level);
self
}
pub fn line_spacing(mut self, spacing: LineSpacing) -> Self {
self.0.paragraph_property = self.0.paragraph_property.line_spacing(spacing.take());
self
}
pub fn keep_next(mut self, v: bool) -> Self {
self.0.paragraph_property = self.0.paragraph_property.keep_next(v);
self
}
pub fn keep_lines(mut self, v: bool) -> Self {
self.0.paragraph_property = self.0.paragraph_property.keep_lines(v);
self
}
pub fn page_break_before(mut self, v: bool) -> Self {
self.0.paragraph_property = self.0.paragraph_property.page_break_before(v);
self
}
pub fn widow_control(mut self, v: bool) -> Self {
self.0.paragraph_property = self.0.paragraph_property.widow_control(v);
self
}
// pub fn run_property(mut self, p: docx_rs::RunProperty) -> Self {
// self.0.run_property = p;
// self
@ -100,6 +170,53 @@ impl Style {
self.0.table_cell_property = p;
self
}
pub fn table_indent(mut self, v: i32) -> Self {
self.0.table_property = self.0.table_property.indent(v);
self
}
pub fn table_align(mut self, v: docx_rs::TableAlignmentType) -> Self {
self.0.table_property = self.0.table_property.align(v);
self
}
pub fn set_cell_margins(
mut self,
top: usize,
right: usize,
bottom: usize,
left: usize,
) -> Self {
let m = docx_rs::TableCellMargins::new().margin(top, right, bottom, left);
self.0.table_property = self.0.table_property.set_margins(m);
self
}
pub fn cell_margin_top(mut self, v: usize, t: WidthType) -> Self {
self.0.table_property = self.0.table_property.cell_margin_top(v, t);
self
}
pub fn cell_margin_right(mut self, v: usize, t: WidthType) -> Self {
self.0.table_property = self.0.table_property.cell_margin_right(v, t);
self
}
pub fn cell_margin_bottom(mut self, v: usize, t: WidthType) -> Self {
self.0.table_property = self.0.table_property.cell_margin_bottom(v, t);
self
}
pub fn cell_margin_left(mut self, v: usize, t: WidthType) -> Self {
self.0.table_property = self.0.table_property.cell_margin_left(v, t);
self
}
pub fn layout(mut self, t: docx_rs::TableLayoutType) -> Self {
self.0.table_property = self.0.table_property.layout(t);
self
}
}
impl Style {

View File

@ -29,6 +29,11 @@ impl Table {
self
}
pub fn style(mut self, style_id: &str) -> Table {
self.0.property = self.0.property.style(style_id);
self
}
pub fn indent(mut self, v: i32) -> Table {
self.0 = self.0.indent(v);
self

View File

@ -67137,6 +67137,23 @@ exports[`writer should write ToC with items 2`] = `
</w:document>"
`;
exports[`writer should write align 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
<Relationship Id=\\"rId1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\\" Target=\\"styles.xml\\" />
<Relationship Id=\\"rId2\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\\" Target=\\"fontTable.xml\\" />
<Relationship Id=\\"rId3\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\\" Target=\\"settings.xml\\" />
<Relationship Id=\\"rId5\\" Type=\\"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\\" Target=\\"commentsExtended.xml\\" />
</Relationships>"
`;
exports[`writer should write align 2`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?>
<w:document xmlns:o=\\"urn:schemas-microsoft-com:office:office\\" xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:v=\\"urn:schemas-microsoft-com:vml\\" xmlns:w=\\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\\" xmlns:w10=\\"urn:schemas-microsoft-com:office:word\\" xmlns:wp=\\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\\" xmlns:wps=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\\" xmlns:wpg=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\\" xmlns:mc=\\"http://schemas.openxmlformats.org/markup-compatibility/2006\\" xmlns:wp14=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\\" xmlns:w14=\\"http://schemas.microsoft.com/office/word/2010/wordml\\" xmlns:w15=\\"http://schemas.microsoft.com/office/word/2012/wordml\\" mc:Ignorable=\\"w14 wp14\\">
<w:body><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /><w:jc w:val=\\"both\\" /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello world!!</w:t></w:r></w:p><w:sectPr><w:pgSz w:w=\\"11906\\" w:h=\\"16838\\" /><w:pgMar w:top=\\"1985\\" w:right=\\"1701\\" w:bottom=\\"1701\\" w:left=\\"1701\\" w:header=\\"851\\" w:footer=\\"992\\" w:gutter=\\"0\\" /><w:cols w:space=\\"425\\" w:num=\\"1\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /></w:sectPr></w:body>
</w:document>"
`;
exports[`writer should write anchor hyperlink 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
@ -67995,6 +68012,37 @@ exports[`writer should write strike 3`] = `
</w:num></w:numbering>"
`;
exports[`writer should write style 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
<Relationship Id=\\"rId1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\\" Target=\\"styles.xml\\" />
<Relationship Id=\\"rId2\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\\" Target=\\"fontTable.xml\\" />
<Relationship Id=\\"rId3\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\\" Target=\\"settings.xml\\" />
<Relationship Id=\\"rId5\\" Type=\\"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\\" Target=\\"commentsExtended.xml\\" />
</Relationships>"
`;
exports[`writer should write style 2`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?>
<w:document xmlns:o=\\"urn:schemas-microsoft-com:office:office\\" xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:v=\\"urn:schemas-microsoft-com:vml\\" xmlns:w=\\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\\" xmlns:w10=\\"urn:schemas-microsoft-com:office:word\\" xmlns:wp=\\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\\" xmlns:wps=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\\" xmlns:wpg=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\\" xmlns:mc=\\"http://schemas.openxmlformats.org/markup-compatibility/2006\\" xmlns:wp14=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\\" xmlns:w14=\\"http://schemas.microsoft.com/office/word/2010/wordml\\" xmlns:w15=\\"http://schemas.microsoft.com/office/word/2012/wordml\\" mc:Ignorable=\\"w14 wp14\\">
<w:body><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /><w:pStyle w:val=\\"Heading1\\" /></w:pPr><w:r><w:rPr><w:rStyle w:val=\\"Run\\" /></w:rPr><w:t xml:space=\\"preserve\\">Hello</w:t></w:r></w:p><w:tbl><w:tblPr><w:tblW w:w=\\"0\\" w:type=\\"dxa\\" /><w:jc w:val=\\"left\\" /><w:tblBorders><w:top w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:left w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:bottom w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:right w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideH w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideV w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /></w:tblBorders><w:tblCellMar>
<w:top w:w=\\"0\\" w:type=\\"dxa\\" />
<w:left w:w=\\"55\\" w:type=\\"dxa\\" />
<w:bottom w:w=\\"0\\" w:type=\\"dxa\\" />
<w:right w:w=\\"55\\" w:type=\\"dxa\\" />
</w:tblCellMar><w:tblInd w:w=\\"0\\" w:type=\\"dxa\\" /><w:tblStyle w:val=\\"Table\\" /></w:tblPr><w:tblGrid /><w:tr><w:trPr /><w:tc><w:tcPr><w:tcBorders><w:top w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:left w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:bottom w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:right w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideH w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideV w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /></w:tcBorders></w:tcPr><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:sectPr><w:pgSz w:w=\\"11906\\" w:h=\\"16838\\" /><w:pgMar w:top=\\"1985\\" w:right=\\"1701\\" w:bottom=\\"1701\\" w:left=\\"1701\\" w:header=\\"851\\" w:footer=\\"992\\" w:gutter=\\"0\\" /><w:cols w:space=\\"425\\" w:num=\\"1\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /></w:sectPr></w:body>
</w:document>"
`;
exports[`writer should write style 3`] = `
"<w:styles xmlns:mc=\\"http://schemas.openxmlformats.org/markup-compatibility/2006\\" xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:w=\\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\\" xmlns:w14=\\"http://schemas.microsoft.com/office/word/2010/wordml\\" xmlns:w15=\\"http://schemas.microsoft.com/office/word/2012/wordml\\" mc:Ignorable=\\"w14 w15\\"><w:docDefaults><w:rPrDefault><w:rPr /></w:rPrDefault></w:docDefaults><w:style w:type=\\"paragraph\\" w:styleId=\\"Normal\\"><w:name w:val=\\"Normal\\" /><w:rPr /><w:pPr><w:rPr /></w:pPr><w:qFormat /></w:style><w:style w:type=\\"paragraph\\" w:styleId=\\"Heading1\\"><w:name w:val=\\"Heading 1\\" /><w:rPr /><w:pPr><w:rPr /><w:jc w:val=\\"center\\" /></w:pPr><w:qFormat /></w:style><w:style w:type=\\"character\\" w:styleId=\\"Run\\"><w:name w:val=\\"Run test\\" /><w:rPr><w:b /><w:bCs /></w:rPr><w:pPr><w:rPr /></w:pPr><w:qFormat /></w:style><w:style w:type=\\"table\\" w:styleId=\\"Table\\"><w:name w:val=\\"Table 1\\" /><w:rPr /><w:pPr><w:rPr /></w:pPr><w:tcPr /><w:tblPr><w:tblW w:w=\\"0\\" w:type=\\"dxa\\" /><w:jc w:val=\\"center\\" /><w:tblBorders><w:top w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:left w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:bottom w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:right w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideH w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideV w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /></w:tblBorders><w:tblCellMar>
<w:top w:w=\\"0\\" w:type=\\"dxa\\" />
<w:left w:w=\\"55\\" w:type=\\"dxa\\" />
<w:bottom w:w=\\"0\\" w:type=\\"dxa\\" />
<w:right w:w=\\"55\\" w:type=\\"dxa\\" />
</w:tblCellMar><w:tblInd w:w=\\"200\\" w:type=\\"dxa\\" /></w:tblPr><w:qFormat /></w:style></w:styles>"
`;
exports[`writer should write table layout 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">

View File

@ -179,6 +179,21 @@ describe("writer", () => {
}
});
test("should write align", () => {
const p = new w.Paragraph()
.addRun(new w.Run().addText("Hello world!!"))
.align("both");
const buffer = new w.Docx().addParagraph(p).build();
const z = new Zip(Buffer.from(buffer));
for (const e of z.getEntries()) {
if (e.entryName.match(/document.xml/)) {
expect(z.readAsText(e)).toMatchSnapshot();
}
}
writeFileSync("../output/js/align.docx", buffer);
});
test("should write strike", () => {
const p = new w.Paragraph().addRun(
new w.Run().addText("Hello world!!").strike()
@ -821,4 +836,44 @@ describe("writer", () => {
}
}
});
test("should write style", () => {
const p = new w.Paragraph()
.addRun(new w.Run().addText("Hello").style("Run"))
.style("Heading1");
const rStyle = new w.Style("Run", "character").name("Run test").bold();
const pStyle = new w.Style("Heading1", "paragraph")
.name("Heading 1")
.align("center");
const tStyle = new w.Style("Table", "table")
.name("Table 1")
.tableAlign("center")
.tableIndent(200);
const table = new w.Table()
.addRow(
new w.TableRow().addCell(
new w.TableCell().addParagraph(
new w.Paragraph().addRun(new w.Run().addText("Hello"))
)
)
)
.style("Table");
const buffer = new w.Docx()
.addStyle(pStyle)
.addStyle(rStyle)
.addStyle(tStyle)
.addParagraph(p)
.addTable(table)
.build();
const z = new Zip(Buffer.from(buffer));
for (const e of z.getEntries()) {
if (e.entryName.match(/document.xml|styles.xml/)) {
expect(z.readAsText(e)).toMatchSnapshot();
}
}
writeFileSync("../output/js/style.docx", buffer);
});
});