Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support tblppr #693

Merged
merged 8 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docx-core/src/documents/elements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ mod table_indent;
mod table_layout;
mod table_of_contents;
mod table_of_contents_item;
mod table_position_property;
mod table_property;
mod table_row;
mod table_row_property;
Expand Down Expand Up @@ -238,6 +239,7 @@ pub use table_indent::*;
pub use table_layout::*;
pub use table_of_contents::*;
pub use table_of_contents_item::*;
pub use table_position_property::*;
pub use table_property::*;
pub use table_row::*;
pub use table_row_property::*;
Expand Down
5 changes: 5 additions & 0 deletions docx-core/src/documents/elements/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ impl Table {
self
}

pub fn position(mut self, p: TablePositionProperty) -> Self {
self.property = self.property.position(p);
self
}

pub fn width(mut self, w: usize, t: WidthType) -> Table {
self.property = self.property.width(w, t);
self
Expand Down
110 changes: 110 additions & 0 deletions docx-core/src/documents/elements/table_position_property.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use serde::Serialize;

use crate::documents::BuildXML;
use crate::xml_builder::*;

/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.tablepositionproperties?view=openxml-3.0.1
#[derive(Debug, Clone, PartialEq, Serialize, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "wasm", derive(ts_rs::TS), ts(export))]
pub struct TablePositionProperty {
#[serde(skip_serializing_if = "Option::is_none")]
pub left_from_text: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right_from_text: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_anchor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_anchor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_x_alignment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_y_alignment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_x: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_y: Option<i32>,
}

impl TablePositionProperty {
pub fn new() -> TablePositionProperty {
Default::default()
}

pub fn left_from_text(mut self, v: i32) -> Self {
self.left_from_text = Some(v);
self
}

pub fn right_from_text(mut self, v: i32) -> Self {
self.right_from_text = Some(v);
self
}

pub fn vertical_anchor(mut self, v: impl Into<String>) -> Self {
self.vertical_anchor = Some(v.into());
self
}

pub fn horizontal_anchor(mut self, v: impl Into<String>) -> Self {
self.horizontal_anchor = Some(v.into());
self
}

pub fn position_x_alignment(mut self, v: impl Into<String>) -> Self {
self.position_x_alignment = Some(v.into());
self
}

pub fn position_y_alignment(mut self, v: impl Into<String>) -> Self {
self.position_y_alignment = Some(v.into());
self
}

pub fn position_x(mut self, v: i32) -> Self {
self.position_x = Some(v);
self
}

pub fn position_y(mut self, v: i32) -> Self {
self.position_y = Some(v);
self
}
}

impl BuildXML for TablePositionProperty {
fn build(&self) -> Vec<u8> {
XMLBuilder::new().table_position_property(self).build()
}
}

#[cfg(test)]
mod tests {

use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;

#[test]
fn test_default() {
let b = TablePositionProperty::new().build();
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:tblpPr />"#);
}

#[test]
fn test_some_attrs() {
let b = TablePositionProperty::new()
.left_from_text(142)
.right_from_text(142)
.vertical_anchor("text")
.horizontal_anchor("margin")
.position_x_alignment("right")
.position_y(511)
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:tblpPr w:leftFromText="142" w:rightFromText="142" w:vertAnchor="text" w:horzAnchor="margin" w:tblpXSpec="right" w:tblpY="511" />"#
);
}
}
9 changes: 9 additions & 0 deletions docx-core/src/documents/elements/table_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub struct TableProperty {
style: Option<TableStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
layout: Option<TableLayout>,
#[serde(skip_serializing_if = "Option::is_none")]
position: Option<TablePositionProperty>,
}

impl Default for TableProperty {
Expand All @@ -34,6 +36,7 @@ impl Default for TableProperty {
indent: None,
style: None,
layout: None,
position: None,
}
}
}
Expand Down Expand Up @@ -139,6 +142,11 @@ impl TableProperty {
self.layout = Some(TableLayout::new(t));
self
}

pub fn position(mut self, p: TablePositionProperty) -> Self {
self.position = Some(p);
self
}
}

impl BuildXML for TableProperty {
Expand All @@ -152,6 +160,7 @@ impl BuildXML for TableProperty {
.add_optional_child(&self.indent)
.add_optional_child(&self.style)
.add_optional_child(&self.layout)
.add_optional_child(&self.position)
.close()
.build()
}
Expand Down
1 change: 1 addition & 0 deletions docx-core/src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ mod table_cell_borders;
mod table_cell_margins;
mod table_cell_property;
mod table_property;
mod table_position_property;
mod table_row;
mod tabs;
mod text_box_content;
Expand Down
5 changes: 5 additions & 0 deletions docx-core/src/reader/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ impl ElementReader for Table {
t = t.width(w as usize, width_type);
continue;
}
XMLElement::TableProperty => {
if let Ok(p) = TableProperty::read(r, &attributes) {
t.property = p;
}
}
XMLElement::Justification => {
t = t.align(TableAlignmentType::from_str(&attributes[0].value)?);
}
Expand Down
55 changes: 55 additions & 0 deletions docx-core/src/reader/table_position_property.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::io::Read;
use std::str::FromStr;

use xml::attribute::OwnedAttribute;
use xml::reader::EventReader;

use super::*;

impl ElementReader for TablePositionProperty {
fn read<R: Read>(
_r: &mut EventReader<R>,
attrs: &[OwnedAttribute],
) -> Result<Self, ReaderError> {
let mut property = TablePositionProperty::new();
for a in attrs {
let local_name = &a.name.local_name;
match local_name.as_str() {
"leftFromText" => {
if let Ok(v) = i32::from_str(&a.value) {
property = property.left_from_text(v);
}
}
"rightFromText" => {
if let Ok(v) = i32::from_str(&a.value) {
property = property.right_from_text(v);
}
}
"vertAnchor" => {
property = property.vertical_anchor(a.value.clone());
}
"horzAnchor" => {
property = property.horizontal_anchor(a.value.clone());
}
"tblpXSpec" => {
property = property.position_x_alignment(a.value.clone());
}
"tblpYSpec" => {
property = property.position_y_alignment(a.value.clone());
}
"tblpX" => {
if let Ok(v) = i32::from_str(&a.value) {
property = property.position_x(v);
}
}
"tblpY" => {
if let Ok(v) = i32::from_str(&a.value) {
property = property.position_y(v);
}
}
_ => {}
}
}
Ok(property)
}
}
30 changes: 30 additions & 0 deletions docx-core/src/reader/table_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ use std::str::FromStr;
use xml::attribute::OwnedAttribute;
use xml::reader::{EventReader, XmlEvent};

use crate::TableAlignmentType;

use super::*;

// TODO: layout: Option<TableLayout>,
impl ElementReader for TableProperty {
fn read<R: Read>(
r: &mut EventReader<R>,
Expand All @@ -31,6 +34,33 @@ impl ElementReader for TableProperty {
tp = tp.set_margins(margins);
}
}
XMLElement::TableWidth => {
if let Ok((w, width_type)) = read_width(&attributes) {
tp = tp.width(w as usize, width_type);
}
}
XMLElement::Justification => {
if let Ok(v) = TableAlignmentType::from_str(&attributes[0].value) {
tp = tp.align(v);
}
}
XMLElement::TableIndent => {
if let Ok((w, _)) = read_width(&attributes) {
if w != 0 {
tp = tp.indent(w as i32);
}
}
}
XMLElement::TableStyle => {
if let Some(s) = read_val(&attributes) {
tp = tp.style(s);
}
}
XMLElement::TablePositionProperty => {
if let Ok(p) = TablePositionProperty::read(r, &attributes) {
tp = tp.position(p);
}
}
_ => {}
}
}
Expand Down
2 changes: 2 additions & 0 deletions docx-core/src/reader/xml_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub enum XMLElement {
TableIndent,
TableBorders,
TableCellMargin,
TablePositionProperty,
TableStyle,
// Change
TableGridChange,
Expand Down Expand Up @@ -327,6 +328,7 @@ impl FromStr for XMLElement {
"tblBorders" => Ok(XMLElement::TableBorders),
"tblCellMar" => Ok(XMLElement::TableCellMargin),
"tblStyle" => Ok(XMLElement::TableStyle),
"tblpPr" => Ok(XMLElement::TablePositionProperty),
"top" => Ok(XMLElement::Top),
"right" => Ok(XMLElement::Right),
"start" => Ok(XMLElement::Start),
Expand Down
48 changes: 48 additions & 0 deletions docx-core/src/xml_builder/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::XMLBuilder;
use super::XmlEvent;
use crate::types::*;
use crate::FrameProperty;
use crate::TablePositionProperty;

const EXPECT_MESSAGE: &str = "should write buf";

Expand Down Expand Up @@ -630,6 +631,53 @@ impl XMLBuilder {
self.close()
}

pub(crate) fn table_position_property(mut self, prop: &TablePositionProperty) -> Self {
let mut w = XmlEvent::start_element("w:tblpPr");

let v: String = format!("{}", prop.left_from_text.unwrap_or_default());
if prop.left_from_text.is_some() {
w = w.attr("w:leftFromText", &v);
}

let v: String = format!("{}", prop.right_from_text.unwrap_or_default());
if prop.right_from_text.is_some() {
w = w.attr("w:rightFromText", &v);
}

let v: String = prop.vertical_anchor.iter().cloned().collect();
if prop.vertical_anchor.is_some() {
w = w.attr("w:vertAnchor", &v);
}

let v: String = prop.horizontal_anchor.iter().cloned().collect();
if prop.horizontal_anchor.is_some() {
w = w.attr("w:horzAnchor", &v);
}

let v: String = prop.position_x_alignment.iter().cloned().collect();
if prop.position_x_alignment.is_some() {
w = w.attr("w:tblpXSpec", &v);
}

let v: String = prop.position_y_alignment.iter().cloned().collect();
if prop.position_y_alignment.is_some() {
w = w.attr("w:tblpYSpec", &v);
}

let v: String = format!("{}", prop.position_x.unwrap_or_default());
if prop.position_x.is_some() {
w = w.attr("w:tblpX", &v);
}

let v: String = format!("{}", prop.position_y.unwrap_or_default());
if prop.position_y.is_some() {
w = w.attr("w:tblpY", &v);
}

self.writer.write(w).expect(EXPECT_MESSAGE);
self.close()
}

pub(crate) fn page_num_type(mut self, start: Option<u32>, chap_style: Option<String>) -> Self {
let mut w = XmlEvent::start_element("w:pgNumType");
let start_string = format!("{}", start.unwrap_or_default());
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docx-core/tests/snapshots/reader__read_insert_table.snap

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docx-wasm/js/json/bindings/TablePositionProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export interface TablePositionProperty { leftFromText?: number, rightFromText?: number, verticalAnchor?: string, horizontalAnchor?: string, positionXAlignment?: string, positionYAlignment?: string, positionX?: number, positionY?: number, }
4 changes: 4 additions & 0 deletions docx-wasm/js/json/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { TableLayoutType } from "../table";
import { DeleteJSONData, InsertJSONData, TableCellBordersJSON } from "..";
import { StructuredTagJSON } from "./structured-data-tag";

import { TablePositionProperty as TablePositionPropertyJSON } from "./bindings/TablePositionProperty";

export { TablePositionProperty as TablePositionPropertyJSON } from "./bindings/TablePositionProperty";
export { TableCellBorder as TableCellBorderJSON } from "./bindings/TableCellBorder";

export { TableCellBorders as TableCellBordersJSON } from "./bindings/TableCellBorders";
Expand Down Expand Up @@ -97,6 +100,7 @@ export type TablePropertyJSON = {
} | null;
style?: string | null;
layout?: TableLayoutType | null;
position?: TablePositionPropertyJSON;
};

export type TableJSON = {
Expand Down
Loading
Loading