Skip to content

Commit

Permalink
Support ptab in r (#756)
Browse files Browse the repository at this point in the history
* feat: add ptab

* feat: wasm object

* fix: suppoert ptab

* spec: add read test for ptab

* rc10

* rc11

* rc12
  • Loading branch information
bokuweb authored Oct 15, 2024
1 parent 19b174d commit 60d9492
Show file tree
Hide file tree
Showing 22 changed files with 573 additions and 5 deletions.
11 changes: 11 additions & 0 deletions docx-core/src/documents/elements/positional_tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@ use crate::xml_builder::*;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[cfg_attr(feature = "wasm", derive(ts_rs::TS))]
#[cfg_attr(feature = "wasm", ts(export))]
#[serde(rename_all = "camelCase")]
pub struct PositionalTab {
pub alignment: PositionalTabAlignmentType,
pub relative_to: PositionalTabRelativeTo,
pub leader: TabLeaderType,
}

impl Default for PositionalTab {
fn default() -> Self {
Self {
alignment: PositionalTabAlignmentType::Left,
relative_to: PositionalTabRelativeTo::Margin,
leader: TabLeaderType::None,
}
}
}

impl PositionalTab {
pub fn new(
alignment: PositionalTabAlignmentType,
Expand Down
13 changes: 13 additions & 0 deletions docx-core/src/documents/elements/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum RunChild {
Sym(Sym),
DeleteText(DeleteText),
Tab(Tab),
PTab(PositionalTab),
Break(Break),
Drawing(Box<Drawing>),
Shape(Box<Shape>),
Expand Down Expand Up @@ -72,6 +73,12 @@ impl Serialize for RunChild {
t.serialize_field("type", "tab")?;
t.end()
}
RunChild::PTab(ref s) => {
let mut t = serializer.serialize_struct("PTab", 1)?;
t.serialize_field("type", "ptab")?;
t.serialize_field("data", s)?;
t.end()
}
RunChild::Break(ref s) => {
let mut t = serializer.serialize_struct("Break", 2)?;
t.serialize_field("type", "break")?;
Expand Down Expand Up @@ -201,6 +208,11 @@ impl Run {
self
}

pub fn add_ptab(mut self, ptab: PositionalTab) -> Run {
self.children.push(RunChild::PTab(ptab));
self
}

pub fn add_image(mut self, pic: Pic) -> Run {
self.children
.push(RunChild::Drawing(Box::new(Drawing::new().pic(pic))));
Expand Down Expand Up @@ -326,6 +338,7 @@ impl BuildXML for Run {
RunChild::Sym(t) => b = b.add_child(t),
RunChild::DeleteText(t) => b = b.add_child(t),
RunChild::Tab(t) => b = b.add_child(t),
RunChild::PTab(t) => b = b.add_child(t),
RunChild::Break(t) => b = b.add_child(t),
RunChild::Drawing(t) => b = b.add_child(t),
RunChild::Shape(_t) => {
Expand Down
3 changes: 2 additions & 1 deletion docx-core/src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod paragraph;
mod paragraph_property;
mod paragraph_property_change;
mod pic;
mod positional_tab;
mod read_zip;
mod rels;
mod run;
Expand All @@ -55,8 +56,8 @@ mod table_cell;
mod table_cell_borders;
mod table_cell_margins;
mod table_cell_property;
mod table_property;
mod table_position_property;
mod table_property;
mod table_row;
mod tabs;
mod text_box_content;
Expand Down
81 changes: 81 additions & 0 deletions docx-core/src/reader/positional_tab.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use std::io::Read;
use std::str::FromStr;

use xml::attribute::OwnedAttribute;
use xml::reader::{EventReader, XmlEvent};

use crate::{PositionalTabAlignmentType, PositionalTabRelativeTo, TabLeaderType};

use super::*;

fn read_leader(attributes: &[OwnedAttribute]) -> Result<TabLeaderType, ReaderError> {
for a in attributes {
let local_name = &a.name.local_name;
if local_name == "leader" {
let v = a.value.to_owned();
if let Ok(t) = TabLeaderType::from_str(&v) {
return Ok(t);
}
}
}
Err(ReaderError::TypeError(crate::TypeError::FromStrError))
}

fn read_alignment(
attributes: &[OwnedAttribute],
) -> Result<PositionalTabAlignmentType, ReaderError> {
for a in attributes {
let local_name = &a.name.local_name;
if local_name == "alignment" {
let v = a.value.to_owned();
if let Ok(t) = PositionalTabAlignmentType::from_str(&v) {
return Ok(t);
}
}
}
Err(ReaderError::TypeError(crate::TypeError::FromStrError))
}

fn read_relative_to(attributes: &[OwnedAttribute]) -> Result<PositionalTabRelativeTo, ReaderError> {
for a in attributes {
let local_name = &a.name.local_name;
if local_name == "alignment" {
let v = a.value.to_owned();
if let Ok(t) = PositionalTabRelativeTo::from_str(&v) {
return Ok(t);
}
}
}
Err(ReaderError::TypeError(crate::TypeError::FromStrError))
}

impl ElementReader for PositionalTab {
fn read<R: Read>(
r: &mut EventReader<R>,
attrs: &[OwnedAttribute],
) -> Result<Self, ReaderError> {
let mut tab = PositionalTab::default();
if let Ok(t) = read_alignment(attrs) {
tab = tab.alignment(t);
}
if let Ok(v) = read_relative_to(attrs) {
tab = tab.relative_to(v);
}
if let Ok(leader) = read_leader(attrs) {
tab = tab.leader(leader);
}
loop {
let e = r.next();
match e {
Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
if e == XMLElement::PTab {
return Ok(tab);
}
}
Err(_) => return Err(ReaderError::XMLReadError),
_ => {}
}
}
}
}
5 changes: 5 additions & 0 deletions docx-core/src/reader/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ impl ElementReader for Run {
XMLElement::Tab => {
run = run.add_tab();
}
XMLElement::PTab => {
if let Ok(v) = PositionalTab::read(r, &attributes) {
run = run.add_ptab(v);
}
}
XMLElement::Sym => {
if let Some(font) = read(&attributes, "font") {
if let Some(char) = read(&attributes, "char") {
Expand Down
5 changes: 5 additions & 0 deletions docx-core/src/reader/run_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ impl ElementReader for RunProperty {
}
rp = rp.caps();
}
XMLElement::PTab => {
if let Ok(v) = PositionalTab::read(r, &attributes) {
rp = rp.ptab(v)
}
}
XMLElement::Highlight => rp = rp.highlight(attributes[0].value.clone()),
XMLElement::Strike => {
if !read_bool(&attributes) {
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 @@ -37,6 +37,7 @@ pub enum XMLElement {
Break,
Tab,
Tabs,
PTab,
Sym,
ParagraphStyle,
ParagraphPropertyChange,
Expand Down Expand Up @@ -289,6 +290,7 @@ impl FromStr for XMLElement {
"name" => Ok(XMLElement::Name),
"tab" => Ok(XMLElement::Tab),
"tabs" => Ok(XMLElement::Tabs),
"ptab" => Ok(XMLElement::PTab),
"br" => Ok(XMLElement::Break),
"ind" => Ok(XMLElement::Indent),
"numPr" => Ok(XMLElement::NumberingProperty),
Expand Down
1 change: 1 addition & 0 deletions docx-core/src/types/positional_tab_relative_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use super::errors;
#[cfg_attr(feature = "wasm", derive(ts_rs::TS))]
#[cfg_attr(feature = "wasm", ts(export))]
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum PositionalTabRelativeTo {
Indent,
Margin,
Expand Down
1 change: 1 addition & 0 deletions docx-wasm/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,3 +672,4 @@ export * from "./page-num";
export * from "./num-pages";
export * from "./footer";
export * from "./image";
export * from "./positional-tab";
2 changes: 1 addition & 1 deletion docx-wasm/js/json/bindings/PositionalTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import type { PositionalTabAlignmentType } from "./PositionalTabAlignmentType";
import type { PositionalTabRelativeTo } from "./PositionalTabRelativeTo";
import type { TabLeaderType } from "./TabLeaderType";

export interface PositionalTab { alignment: PositionalTabAlignmentType, relative_to: PositionalTabRelativeTo, leader: TabLeaderType, }
export interface PositionalTab { alignment: PositionalTabAlignmentType, relativeTo: PositionalTabRelativeTo, leader: TabLeaderType, }
2 changes: 1 addition & 1 deletion docx-wasm/js/json/bindings/PositionalTabRelativeTo.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

export type PositionalTabRelativeTo = "Indent" | "Margin";
export type PositionalTabRelativeTo = "indent" | "margin";
13 changes: 13 additions & 0 deletions docx-wasm/js/json/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import { VertAlignType } from "../run";
import { FieldChar } from "./bindings/FieldChar";
import { InstrHyperlink } from "./bindings/InstrHyperlink";
import { InstrToC } from "./bindings/InstrToC";
import { PositionalTabAlignmentType } from "./bindings/PositionalTabAlignmentType";
import { PositionalTabRelativeTo } from "./bindings/PositionalTabRelativeTo";
import { TabLeaderType } from "./bindings/TabLeaderType";

export type TextBorderJSON = {
borderType: BorderType;
Expand Down Expand Up @@ -61,6 +64,7 @@ export type RunChildJSON =
| TabJSON
| BreakJSON
| DrawingJSON
| PtabJSON
| ShapeJSON
| CommentRangeStartJSON
| CommentRangeEndJSON
Expand All @@ -75,6 +79,15 @@ export type TextJSON = {
};
};

export type PtabJSON = {
type: "ptab";
data: {
alignment: PositionalTabAlignmentType;
relativeTo: PositionalTabRelativeTo;
leader: TabLeaderType;
};
};

export type SymJSON = {
type: "sym";
data: {
Expand Down
50 changes: 50 additions & 0 deletions docx-wasm/js/positional-tab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { PositionalTabAlignmentType } from "./json/bindings/PositionalTabAlignmentType";
import { PositionalTabRelativeTo } from "./json/bindings/PositionalTabRelativeTo";
import { TabLeaderType } from "./json/bindings/TabLeaderType";
import {
createPositionalTab,
PositionalTabAlignmentType as _PositionalTabAlignmentType,
PositionalTabRelativeTo as _PositionalTabRelativeTo,
TabLeaderType as _TabLeaderType,
} from "./pkg/docx_wasm";
import { convertTabLeader } from "./tab-leader";

export class PositionalTab {
_alignment: PositionalTabAlignmentType = "left";
_relativeTo: PositionalTabRelativeTo = "margin";
_leader: TabLeaderType = "none";

alignment(t: PositionalTabAlignmentType) {
this._alignment = t;
return this;
}

relativeTo(t: PositionalTabRelativeTo) {
this._relativeTo = t;
return this;
}

leader(l: TabLeaderType) {
this._leader = l;
return this;
}

buildWasmObject() {
const alignment = (() => {
if (this._alignment === "left") return _PositionalTabAlignmentType.Left;
if (this._alignment === "center")
return _PositionalTabAlignmentType.Center;
if (this._alignment === "right") return _PositionalTabAlignmentType.Right;
return _PositionalTabAlignmentType.Left;
})();

const relativeTo = (() => {
if (this._relativeTo === "indent") return _PositionalTabRelativeTo.Indent;
return _PositionalTabRelativeTo.Margin;
})();

const leader = convertTabLeader(this._leader);

return createPositionalTab(alignment, relativeTo, leader);
}
}
10 changes: 9 additions & 1 deletion docx-wasm/js/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { Tab } from "./tab";
import { Break, BreakType } from "./break";
import { BorderType } from "./border";
import { Image } from "./image";
import { PositionalTab } from "./positional-tab";

export type RunChild = Text | DeleteText | Tab | Break | Image;
export type RunChild = Text | DeleteText | Tab | Break | Image | PositionalTab;

export type TextBorder = {
borderType: BorderType;
Expand Down Expand Up @@ -193,6 +194,11 @@ export class Run {
return this;
}

addPositionalTab(ptab: PositionalTab) {
this.children.push(ptab);
return this;
}

addBreak(type: BreakType) {
this.children.push(new Break(type));
return this;
Expand Down Expand Up @@ -290,6 +296,8 @@ export class Run {
run = run.add_delete_text(child.text);
} else if (child instanceof Tab) {
run = run.add_tab();
} else if (child instanceof PositionalTab) {
run = run.add_ptab(child.buildWasmObject());
} else if (child instanceof Break) {
if (child.type === "column") {
run = run.add_break(wasm.BreakType.Column);
Expand Down
22 changes: 22 additions & 0 deletions docx-wasm/js/tab-leader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as wasm from "./pkg";
import { TabLeaderType } from "./json/bindings/TabLeaderType";

export const convertTabLeader = (leader: TabLeaderType) => {
switch (leader) {
case "dot":
return wasm.TabLeaderType.Dot;
break;
case "heavy":
return wasm.TabLeaderType.Heavy;
case "hyphen":
return wasm.TabLeaderType.Hyphen;
case "middleDot":
return wasm.TabLeaderType.MiddleDot;
case "none":
return wasm.TabLeaderType.None;
case "underscore":
return wasm.TabLeaderType.Underscore;
default:
return wasm.TabLeaderType.None;
}
};
2 changes: 1 addition & 1 deletion docx-wasm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "docx-wasm",
"version": "0.4.18-rc9",
"version": "0.4.18-rc12",
"main": "dist/node/index.js",
"browser": "dist/web/index.js",
"author": "bokuweb <[email protected]>",
Expand Down
2 changes: 2 additions & 0 deletions docx-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod page_num;
mod page_num_type;
mod paragraph;
mod pic;
mod positional_tab;
mod reader;
mod run;
mod run_fonts;
Expand Down Expand Up @@ -49,6 +50,7 @@ pub use page_num::*;
pub use page_num_type::*;
pub use paragraph::*;
pub use pic::*;
pub use positional_tab::*;
pub use reader::*;
pub use run::*;
pub use run_fonts::*;
Expand Down
Loading

0 comments on commit 60d9492

Please sign in to comment.