diff --git a/docx-core/examples/table_border.rs b/docx-core/examples/table_border.rs new file mode 100644 index 0000000..776a931 --- /dev/null +++ b/docx-core/examples/table_border.rs @@ -0,0 +1,44 @@ +use docx_rs::*; + +pub fn main() -> Result<(), DocxError> { + let path = std::path::Path::new("./table_border.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) + .clear_border(BorderPosition::Left) + .clear_border(BorderPosition::Bottom) + .clear_border(BorderPosition::Right), + TableCell::new() + .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))) + .vertical_align(VAlignType::Center) + .vertical_merge(VMergeType::Restart), + ]), + TableRow::new(vec![ + TableCell::new() + .add_paragraph(Paragraph::new()) + .vertical_merge(VMergeType::Restart) + .clear_all_border(), + 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]) + .indent(1000); + Docx::new().add_table(table).build().pack(file)?; + Ok(()) +} diff --git a/docx-core/src/documents/elements/table_cell.rs b/docx-core/src/documents/elements/table_cell.rs index 4ac9042..da3166c 100644 --- a/docx-core/src/documents/elements/table_cell.rs +++ b/docx-core/src/documents/elements/table_cell.rs @@ -1,7 +1,7 @@ use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; -use super::{Paragraph, TableCellProperty}; +use super::*; use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; @@ -67,6 +67,21 @@ impl TableCell { self.property = self.property.width(v, t); self } + + pub fn set_border(mut self, border: TableCellBorder) -> Self { + self.property = self.property.set_border(border); + self + } + + pub fn clear_border(mut self, position: BorderPosition) -> Self { + self.property = self.property.clear_border(position); + self + } + + pub fn clear_all_border(mut self) -> Self { + self.property = self.property.clear_all_border(); + self + } } impl Default for TableCell { @@ -97,7 +112,6 @@ impl BuildXML for TableCell { #[cfg(test)] mod tests { - use super::super::*; use super::*; #[cfg(test)] use pretty_assertions::assert_eq; diff --git a/docx-core/src/documents/elements/table_cell_borders.rs b/docx-core/src/documents/elements/table_cell_borders.rs index b7c1764..5328055 100644 --- a/docx-core/src/documents/elements/table_cell_borders.rs +++ b/docx-core/src/documents/elements/table_cell_borders.rs @@ -16,15 +16,14 @@ use crate::xml_builder::*; tl2br – diagonal border from top left corner to bottom right corner tr2bl – diagonal border from top right corner to bottom left corner */ - #[derive(Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct TableCellBorder { + pub border_type: BorderType, + pub size: usize, + pub color: String, position: BorderPosition, - border_type: BorderType, - size: usize, space: usize, - color: String, } impl TableCellBorder { @@ -42,6 +41,16 @@ impl TableCellBorder { self.color = color.into(); self } + + pub fn size(mut self, size: usize) -> TableCellBorder { + self.size = size; + self + } + + pub fn border_type(mut self, border_type: BorderType) -> TableCellBorder { + self.border_type = border_type; + self + } } impl BuildXML for TableCellBorder { @@ -100,7 +109,7 @@ impl TableCellBorders { Default::default() } - pub fn set_border(mut self, border: TableCellBorder) -> Self { + pub fn set(mut self, border: TableCellBorder) -> Self { match border.position { BorderPosition::Top => self.top = Some(border), BorderPosition::Left => self.left = Some(border), @@ -112,17 +121,31 @@ impl TableCellBorders { self } - pub fn clear_border(mut self, position: BorderPosition) -> Self { + pub fn clear(mut self, position: BorderPosition) -> Self { + let nil = TableCellBorder::new(position.clone()).border_type(BorderType::Nil); match position { - BorderPosition::Top => self.top = None, - BorderPosition::Left => self.left = None, - BorderPosition::Bottom => self.bottom = None, - BorderPosition::Right => self.right = None, - BorderPosition::InsideH => self.inside_h = None, - BorderPosition::InsideV => self.inside_v = None, + BorderPosition::Top => self.top = Some(nil), + BorderPosition::Left => self.left = Some(nil), + BorderPosition::Bottom => self.bottom = Some(nil), + BorderPosition::Right => self.right = Some(nil), + BorderPosition::InsideH => self.inside_h = Some(nil), + BorderPosition::InsideV => self.inside_v = Some(nil), }; self } + + pub fn clear_all(mut self) -> Self { + self.top = Some(TableCellBorder::new(BorderPosition::Top).border_type(BorderType::Nil)); + self.left = Some(TableCellBorder::new(BorderPosition::Left).border_type(BorderType::Nil)); + self.bottom = + Some(TableCellBorder::new(BorderPosition::Bottom).border_type(BorderType::Nil)); + self.right = Some(TableCellBorder::new(BorderPosition::Right).border_type(BorderType::Nil)); + self.inside_h = + Some(TableCellBorder::new(BorderPosition::InsideH).border_type(BorderType::Nil)); + self.inside_v = + Some(TableCellBorder::new(BorderPosition::InsideV).border_type(BorderType::Nil)); + self + } } impl BuildXML for TableCellBorders { diff --git a/docx-core/src/documents/elements/table_cell_property.rs b/docx-core/src/documents/elements/table_cell_property.rs index 67a52d8..acefead 100644 --- a/docx-core/src/documents/elements/table_cell_property.rs +++ b/docx-core/src/documents/elements/table_cell_property.rs @@ -1,6 +1,6 @@ use serde::Serialize; -use super::{GridSpan, TableCellBorders, TableCellWidth, VAlign, VMerge}; +use super::*; use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; @@ -39,6 +39,21 @@ impl TableCellProperty { self.grid_span = Some(GridSpan::new(v)); self } + + pub fn set_border(mut self, border: TableCellBorder) -> Self { + self.borders = Some(self.borders.unwrap_or_default().set(border)); + self + } + + pub fn clear_border(mut self, position: BorderPosition) -> Self { + self.borders = Some(self.borders.unwrap_or_default().clear(position)); + self + } + + pub fn clear_all_border(mut self) -> Self { + self.borders = Some(self.borders.unwrap_or_default().clear_all()); + self + } } impl Default for TableCellProperty { diff --git a/docx-core/src/reader/mod.rs b/docx-core/src/reader/mod.rs index c54c7bc..731bc88 100644 --- a/docx-core/src/reader/mod.rs +++ b/docx-core/src/reader/mod.rs @@ -29,7 +29,6 @@ mod xml_element; mod level_override; use std::io::Cursor; -use zip; use crate::documents::*; diff --git a/docx-core/src/reader/read_zip.rs b/docx-core/src/reader/read_zip.rs index 96294f6..814e33b 100644 --- a/docx-core/src/reader/read_zip.rs +++ b/docx-core/src/reader/read_zip.rs @@ -1,5 +1,4 @@ use std::io::{Cursor, Read}; -use zip; use super::ReaderError; diff --git a/docx-core/src/types/border_position.rs b/docx-core/src/types/border_position.rs index aeb1a65..eb033b5 100644 --- a/docx-core/src/types/border_position.rs +++ b/docx-core/src/types/border_position.rs @@ -1,5 +1,7 @@ +use wasm_bindgen::prelude::*; use serde::Serialize; +#[wasm_bindgen] #[derive(Debug, Clone, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub enum BorderPosition { diff --git a/docx-core/src/types/border_type.rs b/docx-core/src/types/border_type.rs index 963f563..34d1f45 100644 --- a/docx-core/src/types/border_type.rs +++ b/docx-core/src/types/border_type.rs @@ -9,6 +9,7 @@ use wasm_bindgen::prelude::*; #[derive(Copy, Clone, Debug, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub enum BorderType { + Nil, None, Single, Thick, @@ -23,6 +24,7 @@ pub enum BorderType { impl fmt::Display for BorderType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + BorderType::Nil => write!(f, "nil"), BorderType::None => write!(f, "none"), BorderType::Single => write!(f, "single"), BorderType::Thick => write!(f, "thick"), diff --git a/docx-wasm/js/index.ts b/docx-wasm/js/index.ts index 8873673..80fd471 100644 --- a/docx-wasm/js/index.ts +++ b/docx-wasm/js/index.ts @@ -45,7 +45,7 @@ export class Docx { buildRun(r: Run) { let run = wasm.createRun(); - r.children.forEach(child => { + r.children.forEach((child) => { if (child instanceof Text) { run = run.add_text(child.text); } else if (child instanceof DeleteText) { @@ -134,7 +134,7 @@ export class Docx { buildParagraph(p: Paragraph) { let paragraph = wasm.createParagraph(); - p.children.forEach(child => { + p.children.forEach((child) => { if (child instanceof Run) { const run = this.buildRun(child); paragraph = paragraph.add_run(run); @@ -205,9 +205,9 @@ export class Docx { buildTable(t: Table) { let table = wasm.createTable(); - t.rows.forEach(r => { + t.rows.forEach((r) => { let row = wasm.createTableRow(); - r.cells.forEach(c => { + r.cells.forEach((c) => { const cell = this.buildCell(c); row = row.add_cell(cell); }); @@ -237,7 +237,7 @@ export class Docx { buildCell(c: TableCell) { let cell = wasm.createTableCell(); - c.children.forEach(p => { + c.children.forEach((p) => { const paragraph = this.buildParagraph(p); cell = cell.add_paragraph(paragraph); }); @@ -270,12 +270,68 @@ export class Docx { 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(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(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(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(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(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(c.property.borders.insideV.border_type); + cell = cell.set_border(border); + } + } + return cell; } build() { let docx = wasm.createDocx(); - this.children.forEach(child => { + this.children.forEach((child) => { if (child instanceof Paragraph) { let p = this.buildParagraph(child); docx = docx.add_paragraph(p); @@ -285,16 +341,16 @@ export class Docx { } }); - this.abstractNumberings.forEach(n => { + this.abstractNumberings.forEach((n) => { let num = wasm.createAbstractNumbering(n.id); - n.levels.forEach(l => { + n.levels.forEach((l) => { const level = wasm.createLevel(l.id, l.start, l.format, l.text, l.jc); num = num.add_level(level); }); docx = docx.add_abstract_numbering(num); }); - this.numberings.forEach(n => { + this.numberings.forEach((n) => { let num = wasm.createNumbering(n.id, n.abstractNumId); docx = docx.add_numbering(num); }); diff --git a/docx-wasm/js/table-cell-border.ts b/docx-wasm/js/table-cell-border.ts new file mode 100644 index 0000000..7cebd6b --- /dev/null +++ b/docx-wasm/js/table-cell-border.ts @@ -0,0 +1,46 @@ +export type BorderType = + | "Nil" + | "None" + | "Single" + | "Thick" + | "Double" + | "Dotted" + | "Dashed" + | "DotDash" + | "DotDotDash" + | "Triple"; + +export type BorderPosition = + | "Left" + | "Right" + | "Top" + | "Bottom" + | "InsideH" + | "InsideV"; + +export class TableCellBorder { + _border_type: BorderType; + _size = 2; + _color = "000000"; + position: BorderPosition; + space = 0; + + constructor(position: BorderPosition) { + this.position = position; + } + + color(color: string) { + this._color = color; + return this; + } + + size(size: number) { + this._size = size; + return this; + } + + border_type(border_type: BorderType) { + this._border_type = border_type; + return this; + } +} diff --git a/docx-wasm/js/table-cell-borders.ts b/docx-wasm/js/table-cell-borders.ts new file mode 100644 index 0000000..007e86a --- /dev/null +++ b/docx-wasm/js/table-cell-borders.ts @@ -0,0 +1,57 @@ +import { BorderPosition, TableCellBorder } from "./table-cell-border"; + +export class TableCellBorders { + top: TableCellBorder | null = new TableCellBorder("Top"); + left: TableCellBorder | null = new TableCellBorder("Left"); + bottom: TableCellBorder | null = new TableCellBorder("Bottom"); + right: TableCellBorder | null = new TableCellBorder("Right"); + insideH: TableCellBorder | null = new TableCellBorder("InsideH"); + insideV: TableCellBorder | null = new TableCellBorder("InsideV"); + + set(border: TableCellBorder) { + switch (border.position) { + case "Top": + this.top = border; + case "Left": + this.left = border; + case "Bottom": + this.bottom = border; + case "Right": + this.right = border; + case "InsideH": + this.insideH = border; + case "InsideV": + this.insideV = border; + } + return this; + } + + clear(position: BorderPosition) { + let nil = new TableCellBorder(position).border_type("Nil"); + switch (position) { + case "Top": + this.top = nil; + case "Left": + this.left = nil; + case "Bottom": + this.bottom = nil; + case "Right": + this.right = nil; + case "InsideH": + this.insideH = nil; + case "InsideV": + this.insideV = nil; + } + return this; + } + + clearAll() { + this.top = new TableCellBorder("Top").border_type("Nil"); + this.left = new TableCellBorder("Left").border_type("Nil"); + this.bottom = new TableCellBorder("Bottom").border_type("Nil"); + this.right = new TableCellBorder("Right").border_type("Nil"); + this.insideH = new TableCellBorder("InsideH").border_type("Nil"); + this.insideV = new TableCellBorder("InsideV").border_type("Nil"); + return this; + } +} diff --git a/docx-wasm/js/table-cell.ts b/docx-wasm/js/table-cell.ts index 28db6aa..6344769 100644 --- a/docx-wasm/js/table-cell.ts +++ b/docx-wasm/js/table-cell.ts @@ -1,10 +1,13 @@ import { Paragraph } from "./paragraph"; +import { TableCellBorders } from "./table-cell-borders"; +import { BorderPosition, TableCellBorder } from "./table-cell-border"; export type VMergeType = "restart" | "continue"; export type VAlignType = "top" | "center" | "bottom"; export type CellProperty = { + borders?: TableCellBorders; verticalMerge?: VMergeType; verticalAlign?: VAlignType; gridSpan?: number; @@ -39,4 +42,16 @@ export class TableCell { this.property.width = v; return this; } + + setBorder(position: BorderPosition, border: TableCellBorder) { + this.property.borders[position] = border; + return this; + } + + clearBorder(position: BorderPosition) { + this.property.borders[position] = new TableCellBorder(position).border_type( + "Nil" + ); + return this; + } } diff --git a/docx-wasm/src/abstract_numbering.rs b/docx-wasm/src/abstract_numbering.rs index 035dcec..e30504c 100644 --- a/docx-wasm/src/abstract_numbering.rs +++ b/docx-wasm/src/abstract_numbering.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/adaptors/special_indent.rs b/docx-wasm/src/adaptors/special_indent.rs index 66672a5..886c46e 100644 --- a/docx-wasm/src/adaptors/special_indent.rs +++ b/docx-wasm/src/adaptors/special_indent.rs @@ -1,5 +1,3 @@ -use docx_rs; - pub fn create_special_indent( special_indent_kind: Option, special_indent_size: Option, diff --git a/docx-wasm/src/comment.rs b/docx-wasm/src/comment.rs index 26deb30..2cf5ca9 100644 --- a/docx-wasm/src/comment.rs +++ b/docx-wasm/src/comment.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/delete.rs b/docx-wasm/src/delete.rs index 9f9e167..2cabe65 100644 --- a/docx-wasm/src/delete.rs +++ b/docx-wasm/src/delete.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/doc.rs b/docx-wasm/src/doc.rs index faf4511..4ee6db0 100644 --- a/docx-wasm/src/doc.rs +++ b/docx-wasm/src/doc.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/insert.rs b/docx-wasm/src/insert.rs index c79198e..ec91823 100644 --- a/docx-wasm/src/insert.rs +++ b/docx-wasm/src/insert.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/level.rs b/docx-wasm/src/level.rs index 6f8bdb3..4029697 100644 --- a/docx-wasm/src/level.rs +++ b/docx-wasm/src/level.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/lib.rs b/docx-wasm/src/lib.rs index 3281119..e34387b 100644 --- a/docx-wasm/src/lib.rs +++ b/docx-wasm/src/lib.rs @@ -12,6 +12,7 @@ mod run; mod table; mod table_cell; mod table_row; +mod table_cell_border; pub use abstract_numbering::*; pub use adaptors::*; @@ -27,3 +28,4 @@ pub use run::*; pub use table::*; pub use table_cell::*; pub use table_row::*; +pub use table_cell_border::*; \ No newline at end of file diff --git a/docx-wasm/src/numbering.rs b/docx-wasm/src/numbering.rs index a9b20be..fc14159 100644 --- a/docx-wasm/src/numbering.rs +++ b/docx-wasm/src/numbering.rs @@ -1,4 +1,3 @@ -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/paragraph.rs b/docx-wasm/src/paragraph.rs index 120a951..e4c654c 100644 --- a/docx-wasm/src/paragraph.rs +++ b/docx-wasm/src/paragraph.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/reader.rs b/docx-wasm/src/reader.rs index 5102b31..5fdcfac 100644 --- a/docx-wasm/src/reader.rs +++ b/docx-wasm/src/reader.rs @@ -1,4 +1,3 @@ -use docx_rs; use wasm_bindgen::prelude::*; #[allow(non_snake_case)] diff --git a/docx-wasm/src/run.rs b/docx-wasm/src/run.rs index cc4991c..dc652e3 100644 --- a/docx-wasm/src/run.rs +++ b/docx-wasm/src/run.rs @@ -1,4 +1,3 @@ -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/table.rs b/docx-wasm/src/table.rs index 3561bad..fea4990 100644 --- a/docx-wasm/src/table.rs +++ b/docx-wasm/src/table.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] diff --git a/docx-wasm/src/table_cell.rs b/docx-wasm/src/table_cell.rs index 253282f..c709cad 100644 --- a/docx-wasm/src/table_cell.rs +++ b/docx-wasm/src/table_cell.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -45,4 +44,19 @@ impl TableCell { self.0.property = self.0.property.width(v, docx_rs::WidthType::DXA); self } + + pub fn set_border(mut self, border: TableCellBorder) -> TableCell { + self.0.property = self.0.property.set_border(border.take()); + self + } + + pub fn clear_border(mut self, position: docx_rs::BorderPosition) -> TableCell { + self.0.property = self.0.property.clear_border(position); + self + } + + pub fn clear_all_border(mut self) -> TableCell { + self.0.property = self.0.property.clear_all_border(); + self + } } diff --git a/docx-wasm/src/table_cell_border.rs b/docx-wasm/src/table_cell_border.rs new file mode 100644 index 0000000..32642ac --- /dev/null +++ b/docx-wasm/src/table_cell_border.rs @@ -0,0 +1,29 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[derive(Debug)] +pub struct TableCellBorder(docx_rs::TableCellBorder); + +#[wasm_bindgen(js_name = createTableCellBorder)] +pub fn create_table_cell_border(position: docx_rs::BorderPosition) -> TableCellBorder { + TableCellBorder(docx_rs::TableCellBorder::new(position)) +} + +impl TableCellBorder { + pub fn take(self) -> docx_rs::TableCellBorder { + self.0 + } +} + +#[wasm_bindgen] +impl TableCellBorder { + pub fn color(mut self, color: String) -> TableCellBorder { + self.0.color = color; + self + } + + pub fn border_type(mut self, border_type: docx_rs::BorderType) -> TableCellBorder { + self.0.border_type = border_type; + self + } +} diff --git a/docx-wasm/src/table_row.rs b/docx-wasm/src/table_row.rs index 19ecdbc..6d4e3b5 100644 --- a/docx-wasm/src/table_row.rs +++ b/docx-wasm/src/table_row.rs @@ -1,5 +1,4 @@ use super::*; -use docx_rs; use wasm_bindgen::prelude::*; #[wasm_bindgen]