Support table cell margin (#275)

* fix: writer

* fix: reader

* fix: update snaps
main
bokuweb 2021-04-14 13:47:46 +09:00 committed by GitHub
parent 5402fe2190
commit ee41237378
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 891 additions and 233 deletions

View File

@ -127,7 +127,7 @@ mod tests {
str::from_utf8(&b).unwrap(),
r#"<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="55" w:type="dxa" />
<w:left w:w="54" w:type="dxa" />
<w:left w:w="55" w:type="dxa" />
<w:bottom w:w="55" w:type="dxa" />
<w:right w:w="55" w:type="dxa" />
</w:tblCellMar></w:tblPr><w:tblGrid /><w:tr><w:trPr /></w:tr></w:tbl>"#
@ -143,7 +143,7 @@ mod tests {
str::from_utf8(&b).unwrap(),
r#"<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="55" w:type="dxa" />
<w:left w:w="54" w:type="dxa" />
<w:left w:w="55" w:type="dxa" />
<w:bottom w:w="55" w:type="dxa" />
<w:right w:w="55" w:type="dxa" />
</w:tblCellMar></w:tblPr><w:tblGrid>
@ -158,7 +158,7 @@ mod tests {
let t = Table::new(vec![]).set_grid(vec![100, 200, 300]);
assert_eq!(
serde_json::to_string(&t).unwrap(),
r#"{"rows":[],"grid":[100,200,300],"hasNumbering":false,"property":{"width":{"width":0,"widthType":"Auto"},"justification":"left","borders":{"top":{"borderType":"single","size":2,"color":"000000","position":"top","space":0},"left":{"borderType":"single","size":2,"color":"000000","position":"left","space":0},"bottom":{"borderType":"single","size":2,"color":"000000","position":"bottom","space":0},"right":{"borderType":"single","size":2,"color":"000000","position":"right","space":0},"insideH":{"borderType":"single","size":2,"color":"000000","position":"insideH","space":0},"insideV":{"borderType":"single","size":2,"color":"000000","position":"insideV","space":0}},"margins":{"top":55,"left":54,"bottom":55,"right":55},"indent":null,"style":null,"layout":null}}"#
r#"{"rows":[],"grid":[100,200,300],"hasNumbering":false,"property":{"width":{"width":0,"widthType":"Auto"},"justification":"left","borders":{"top":{"borderType":"single","size":2,"color":"000000","position":"top","space":0},"left":{"borderType":"single","size":2,"color":"000000","position":"left","space":0},"bottom":{"borderType":"single","size":2,"color":"000000","position":"bottom","space":0},"right":{"borderType":"single","size":2,"color":"000000","position":"right","space":0},"insideH":{"borderType":"single","size":2,"color":"000000","position":"insideH","space":0},"insideV":{"borderType":"single","size":2,"color":"000000","position":"insideV","space":0}},"margins":{"top":{"val":55,"widthType":"DXA"},"left":{"val":55,"widthType":"DXA"},"bottom":{"val":55,"widthType":"DXA"},"right":{"val":55,"widthType":"DXA"}},"indent":null,"style":null,"layout":null}}"#
);
}
}

View File

@ -4,22 +4,44 @@ use crate::documents::BuildXML;
use crate::types::*;
use crate::xml_builder::*;
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
struct CellMargin {
pub val: usize,
pub width_type: WidthType,
}
impl CellMargin {
pub fn new(val: usize, t: WidthType) -> Self {
Self { val, width_type: t }
}
}
impl Default for CellMargin {
fn default() -> CellMargin {
CellMargin {
val: 55,
width_type: WidthType::DXA,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TableCellMargins {
top: usize,
left: usize,
bottom: usize,
right: usize,
top: CellMargin,
left: CellMargin,
bottom: CellMargin,
right: CellMargin,
}
impl Default for TableCellMargins {
fn default() -> TableCellMargins {
TableCellMargins {
top: 55,
left: 54,
bottom: 55,
right: 55,
top: CellMargin::default(),
left: CellMargin::default(),
bottom: CellMargin::default(),
right: CellMargin::default(),
}
}
}
@ -31,22 +53,42 @@ impl TableCellMargins {
pub fn margin(self, top: usize, right: usize, bottom: usize, left: usize) -> TableCellMargins {
TableCellMargins {
top,
left,
bottom,
right,
top: CellMargin::new(top, WidthType::DXA),
left: CellMargin::new(left, WidthType::DXA),
bottom: CellMargin::new(bottom, WidthType::DXA),
right: CellMargin::new(right, WidthType::DXA),
}
}
pub fn margin_top(mut self, v: usize, t: WidthType) -> Self {
self.top = CellMargin::new(v, t);
self
}
pub fn margin_right(mut self, v: usize, t: WidthType) -> Self {
self.right = CellMargin::new(v, t);
self
}
pub fn margin_left(mut self, v: usize, t: WidthType) -> Self {
self.left = CellMargin::new(v, t);
self
}
pub fn margin_bottom(mut self, v: usize, t: WidthType) -> Self {
self.bottom = CellMargin::new(v, t);
self
}
}
impl BuildXML for TableCellMargins {
fn build(&self) -> Vec<u8> {
XMLBuilder::new()
.open_table_cell_margins()
.margin_top(self.top as i32, WidthType::DXA)
.margin_left(self.left as i32, WidthType::DXA)
.margin_bottom(self.bottom as i32, WidthType::DXA)
.margin_right(self.right as i32, WidthType::DXA)
.margin_top(self.top.val as i32, self.top.width_type)
.margin_left(self.left.val as i32, self.left.width_type)
.margin_bottom(self.bottom.val as i32, self.bottom.width_type)
.margin_right(self.right.val as i32, self.right.width_type)
.close()
.build()
}
@ -67,7 +109,7 @@ mod tests {
str::from_utf8(&b).unwrap(),
r#"<w:tblCellMar>
<w:top w:w="55" w:type="dxa" />
<w:left w:w="54" w:type="dxa" />
<w:left w:w="55" w:type="dxa" />
<w:bottom w:w="55" w:type="dxa" />
<w:right w:w="55" w:type="dxa" />
</w:tblCellMar>"#

View File

@ -63,6 +63,26 @@ impl TableProperty {
self
}
pub fn cell_margin_top(mut self, v: usize, t: WidthType) -> Self {
self.margins = self.margins.margin_top(v, t);
self
}
pub fn cell_margin_right(mut self, v: usize, t: WidthType) -> Self {
self.margins = self.margins.margin_right(v, t);
self
}
pub fn cell_margin_bottom(mut self, v: usize, t: WidthType) -> Self {
self.margins = self.margins.margin_bottom(v, t);
self
}
pub fn cell_margin_left(mut self, v: usize, t: WidthType) -> Self {
self.margins = self.margins.margin_left(v, t);
self
}
pub fn set_borders(mut self, borders: TableBorders) -> Self {
self.borders = borders;
self
@ -126,7 +146,7 @@ mod tests {
str::from_utf8(&b).unwrap(),
r#"<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="55" w:type="dxa" />
<w:left w:w="54" w:type="dxa" />
<w:left w:w="55" w:type="dxa" />
<w:bottom w:w="55" w:type="dxa" />
<w:right w:w="55" w:type="dxa" />
</w:tblCellMar></w:tblPr>"#
@ -138,7 +158,7 @@ mod tests {
let p = TableProperty::new().indent(100);
assert_eq!(
serde_json::to_string(&p).unwrap(),
r#"{"width":{"width":0,"widthType":"Auto"},"justification":"left","borders":{"top":{"borderType":"single","size":2,"color":"000000","position":"top","space":0},"left":{"borderType":"single","size":2,"color":"000000","position":"left","space":0},"bottom":{"borderType":"single","size":2,"color":"000000","position":"bottom","space":0},"right":{"borderType":"single","size":2,"color":"000000","position":"right","space":0},"insideH":{"borderType":"single","size":2,"color":"000000","position":"insideH","space":0},"insideV":{"borderType":"single","size":2,"color":"000000","position":"insideV","space":0}},"margins":{"top":55,"left":54,"bottom":55,"right":55},"indent":{"width":100,"widthType":"DXA"},"style":null,"layout":null}"#
r#"{"width":{"width":0,"widthType":"Auto"},"justification":"left","borders":{"top":{"borderType":"single","size":2,"color":"000000","position":"top","space":0},"left":{"borderType":"single","size":2,"color":"000000","position":"left","space":0},"bottom":{"borderType":"single","size":2,"color":"000000","position":"bottom","space":0},"right":{"borderType":"single","size":2,"color":"000000","position":"right","space":0},"insideH":{"borderType":"single","size":2,"color":"000000","position":"insideH","space":0},"insideV":{"borderType":"single","size":2,"color":"000000","position":"insideV","space":0}},"margins":{"top":{"val":55,"widthType":"DXA"},"left":{"val":55,"widthType":"DXA"},"bottom":{"val":55,"widthType":"DXA"},"right":{"val":55,"widthType":"DXA"}},"indent":{"width":100,"widthType":"DXA"},"style":null,"layout":null}"#
);
}
}

View File

@ -37,6 +37,7 @@ mod table;
mod table_borders;
mod table_cell;
mod table_cell_borders;
mod table_cell_margins;
mod table_cell_property;
mod table_property;
mod table_row;

View File

@ -51,7 +51,9 @@ impl ElementReader for Table {
}
}
XMLElement::TableCellMargin => {
// TODO: Support later
if let Ok(margins) = TableCellMargins::read(r, &attributes) {
t = t.margins(margins)
}
}
XMLElement::GridCol => {
let (w, _) = read_width(&attributes)?;

View File

@ -0,0 +1,54 @@
use std::io::Read;
use std::str::FromStr;
use xml::attribute::OwnedAttribute;
use xml::reader::{EventReader, XmlEvent};
use super::*;
impl ElementReader for TableCellMargins {
fn read<R: Read>(r: &mut EventReader<R>, _: &[OwnedAttribute]) -> Result<Self, ReaderError> {
let mut margins = TableCellMargins::default();
loop {
let e = r.next();
match e {
Ok(XmlEvent::StartElement {
attributes, name, ..
}) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
match e {
XMLElement::Top => {
if let Ok(width) = read_width(&attributes) {
margins = margins.margin_top(width.0 as usize, width.1)
}
}
XMLElement::Right => {
if let Ok(width) = read_width(&attributes) {
margins = margins.margin_right(width.0 as usize, width.1)
}
}
XMLElement::Bottom => {
if let Ok(width) = read_width(&attributes) {
margins = margins.margin_bottom(width.0 as usize, width.1)
}
}
XMLElement::Left => {
if let Ok(width) = read_width(&attributes) {
margins = margins.margin_left(width.0 as usize, width.1)
}
}
_ => {}
}
}
Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
if e == XMLElement::TableCellMargin {
return Ok(margins);
}
}
Err(_) => return Err(ReaderError::XMLReadError),
_ => {}
}
}
}
}

View File

@ -78,6 +78,7 @@ pub enum XMLElement {
TableWidth,
TableIndent,
TableBorders,
TableCellMargin,
TableStyle,
// Change
TableGridChange,
@ -94,7 +95,6 @@ pub enum XMLElement {
InsideV,
Tl2br,
Tr2bl,
TableCellMargin,
TableGrid,
GridCol,
GridAfter,
@ -250,6 +250,7 @@ impl FromStr for XMLElement {
"tblW" => Ok(XMLElement::TableWidth),
"tblInd" => Ok(XMLElement::TableIndent),
"tblBorders" => Ok(XMLElement::TableBorders),
"tblCellMar" => Ok(XMLElement::TableCellMargin),
"tblStyle" => Ok(XMLElement::TableStyle),
"top" => Ok(XMLElement::Top),
"right" => Ok(XMLElement::Right),
@ -261,7 +262,6 @@ impl FromStr for XMLElement {
"insideV" => Ok(XMLElement::InsideV),
"tl2br" => Ok(XMLElement::Tl2br),
"tr2bl" => Ok(XMLElement::Tr2bl),
"tblCellMar" => Ok(XMLElement::TableCellMargin),
"tblGrid" => Ok(XMLElement::TableGrid),
"tblPrChange" => Ok(XMLElement::TablePropertyChange),
"trPrChange" => Ok(XMLElement::TableRowPropertyChange),

View File

@ -11,6 +11,7 @@ pub enum WidthType {
DXA,
Auto,
Pct,
Nil,
Unsupported,
}
@ -20,6 +21,7 @@ impl fmt::Display for WidthType {
WidthType::DXA => write!(f, "dxa"),
WidthType::Auto => write!(f, "auto"),
WidthType::Pct => write!(f, "pct"),
WidthType::Nil => write!(f, "nil"),
WidthType::Unsupported => write!(f, "unsupported"),
}
}
@ -32,6 +34,7 @@ impl FromStr for WidthType {
"dxa" => Ok(WidthType::DXA),
"auto" => Ok(WidthType::Auto),
"pct" => Ok(WidthType::Pct),
"nil" => Ok(WidthType::Nil),
_ => Ok(WidthType::Unsupported),
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -23,7 +23,7 @@ import {
PageMargin,
PageOrientationType,
} from "./section-property";
import { DocGridType, DocxJSON } from "./json";
import { DocGridType, DocxJSON, WidthType } from "./json";
import * as wasm from "./pkg";
import { Level } from "./level";
@ -55,6 +55,21 @@ const convertBorderType = (t: BorderType) => {
}
};
const convertWidthType = (t: WidthType) => {
switch (t) {
case "nil":
return wasm.WidthType.Nil;
case "Pct":
return wasm.WidthType.Pct;
case "DXA":
return wasm.WidthType.DXA;
case "Auto":
return wasm.WidthType.Auto;
default:
return wasm.WidthType.DXA;
}
};
export class Docx {
children: (Paragraph | Table | BookmarkStart | BookmarkEnd)[] = [];
hasNumberings = false;
@ -454,7 +469,11 @@ export class Docx {
if (t.property.cellMargins) {
const { top, right, bottom, left } = t.property.cellMargins;
table = table.set_cell_margins(top, right, bottom, left);
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));
}
switch (t.property.align) {

View File

@ -7,7 +7,7 @@ import { TableLayoutType } from "../table";
export type TableCellChildJSON = ParagraphJSON;
export type WidthType = "DXA" | "Auto" | "Pct";
export type WidthType = "DXA" | "Auto" | "Pct" | "nil";
export { TextDirectionType } from "../table-cell";
export { HeightRule } from "../table-row";
@ -58,10 +58,10 @@ export type TablePropertyJSON = {
insideV: BorderJSON;
} | null;
margins: {
top: number;
left: number;
bottom: number;
right: number;
top: { val: number; widthType: WidthType };
left: { val: number; widthType: WidthType };
bottom: { val: number; widthType: WidthType };
right: { val: number; widthType: WidthType };
} | null;
indent: {
width: number;

View File

@ -1,6 +1,6 @@
import { createDefaultTableCellMargins, TableProperty } from "./table";
import { RunProperty, createDefaultRunProperty } from "./run";
import { createDefaultParagraphProperty, ParagraphProperty } from "./paragraph";
import { TableProperty } from "./table";
export type StyleType =
| "paragraph"
@ -22,9 +22,12 @@ export class Style {
this._styleId = id;
this._styleType = type;
this._name = "";
this._runProperty = {};
this._tableProperty = {
cellMargins: createDefaultTableCellMargins(),
};
this._runProperty = createDefaultRunProperty();
this._paragraphProperty = createDefaultParagraphProperty();
this._tableProperty = {};
this._basedOn = null;
}

View File

@ -1,3 +1,4 @@
import { WidthType } from ".";
import { TableRow } from "./table-row";
export type TableAlignmentType = "center" | "left" | "right";
@ -7,20 +8,31 @@ export type TableProperty = {
indent?: number;
align?: TableAlignmentType;
width?: number;
cellMargins?: {
top: number;
left: number;
bottom: number;
right: number;
cellMargins: {
top: { val: number; type: WidthType };
left: { val: number; type: WidthType };
bottom: { val: number; type: WidthType };
right: { val: number; type: WidthType };
};
layout?: TableLayoutType;
};
export const createDefaultTableCellMargins = () => {
return {
top: { val: 55, type: "DXA" },
left: { val: 55, type: "DXA" },
bottom: { val: 55, type: "DXA" },
right: { val: 55, type: "DXA" },
} as const;
};
export class Table {
hasNumberings = false;
rows: TableRow[] = [];
grid: number[] = [];
property: TableProperty = {};
property: TableProperty = {
cellMargins: createDefaultTableCellMargins(),
};
addRow(row: TableRow) {
if (row.hasNumberings) {
@ -56,7 +68,32 @@ export class Table {
}
cellMargins(top: number, right: number, bottom: number, left: number) {
this.property.cellMargins = { top, left, bottom, right };
this.property.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.property.cellMargins.top = { val: v, type: t };
return this;
}
cellMarginLeft(v: number, t: WidthType) {
this.property.cellMargins.left = { val: v, type: t };
return this;
}
cellMarginRight(v: number, t: WidthType) {
this.property.cellMargins.right = { val: v, type: t };
return this;
}
cellMarginBottom(v: number, t: WidthType) {
this.property.cellMargins.bottom = { val: v, type: t };
return this;
}
}

View File

@ -1,6 +1,6 @@
{
"name": "docx-wasm",
"version": "0.0.190",
"version": "0.0.191",
"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::WidthType;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
@ -59,4 +60,24 @@ impl Table {
self.0.property = self.0.property.set_margins(m);
self
}
pub fn cell_margin_top(mut self, v: usize, t: WidthType) -> Table {
self.0.property = self.0.property.cell_margin_top(v, t);
self
}
pub fn cell_margin_right(mut self, v: usize, t: WidthType) -> Table {
self.0.property = self.0.property.cell_margin_right(v, t);
self
}
pub fn cell_margin_bottom(mut self, v: usize, t: WidthType) -> Table {
self.0.property = self.0.property.cell_margin_bottom(v, t);
self
}
pub fn cell_margin_left(mut self, v: usize, t: WidthType) -> Table {
self.0.property = self.0.property.cell_margin_left(v, t);
self
}
}

File diff suppressed because it is too large Load Diff