feat: Support table cell border (#63)

* feat: Support table cell border

* fix: lint

* fix: lint error
main
bokuweb 2020-04-27 10:41:23 +09:00 committed by GitHub
parent 6e9c10b385
commit 5c6d95aaf7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 344 additions and 41 deletions

View File

@ -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(())
}

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -29,7 +29,6 @@ mod xml_element;
mod level_override;
use std::io::Cursor;
use zip;
use crate::documents::*;

View File

@ -1,5 +1,4 @@
use std::io::{Cursor, Read};
use zip;
use super::ReaderError;

View File

@ -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 {

View File

@ -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"),

View File

@ -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);
});

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,3 @@
use docx_rs;
pub fn create_special_indent(
special_indent_kind: Option<docx_rs::SpecialIndentKind>,
special_indent_size: Option<i32>,

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -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::*;

View File

@ -1,4 +1,3 @@
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,4 +1,3 @@
use docx_rs;
use wasm_bindgen::prelude::*;
#[allow(non_snake_case)]

View File

@ -1,4 +1,3 @@
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -1,5 +1,4 @@
use super::*;
use docx_rs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]