diff --git a/docx-core/examples/header_with_page_num.rs b/docx-core/examples/header_with_page_num.rs index ed700e8..d3340aa 100644 --- a/docx-core/examples/header_with_page_num.rs +++ b/docx-core/examples/header_with_page_num.rs @@ -3,16 +3,15 @@ use docx_rs::*; pub fn main() -> Result<(), DocxError> { let path = std::path::Path::new("./output/examples/header_with_page_num.docx"); let file = std::fs::File::create(path).unwrap(); - let header = Header::new() - .add_page_num( - PageNum::new() - .wrap("none") - .v_anchor("text") - .h_anchor("margin") - .x_align("right") - .y(1), - ) - .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))); + let header = Header::new().add_paragraph( + Paragraph::new() + .wrap("none") + .v_anchor("text") + .h_anchor("margin") + .x_align("right") + .add_run(Run::new().add_text("Hello")) + .add_page_num(PageNum::new()), + ); Docx::new() .header(header) .add_paragraph(Paragraph::new().add_run(Run::new().add_text("World"))) diff --git a/docx-core/src/documents/elements/instr_num_pages.rs b/docx-core/src/documents/elements/instr_num_pages.rs new file mode 100644 index 0000000..bca1c96 --- /dev/null +++ b/docx-core/src/documents/elements/instr_num_pages.rs @@ -0,0 +1,20 @@ +use serde::Serialize; + +use crate::documents::*; + +#[derive(Serialize, Debug, Clone, PartialEq, Default)] +#[serde(rename_all = "camelCase")] +pub struct InstrNUMPAGES {} + +impl InstrNUMPAGES { + pub fn new() -> Self { + Self {} + } +} + +impl BuildXML for InstrNUMPAGES { + fn build(&self) -> Vec { + let instr = "NUMPAGES".to_owned(); + instr.into() + } +} diff --git a/docx-core/src/documents/elements/instr_text.rs b/docx-core/src/documents/elements/instr_text.rs index 2ca84d4..e3db9f2 100644 --- a/docx-core/src/documents/elements/instr_text.rs +++ b/docx-core/src/documents/elements/instr_text.rs @@ -9,6 +9,7 @@ pub enum InstrText { TOC(InstrToC), TC(InstrTC), PAGE(InstrPAGE), + NUMPAGES(InstrNUMPAGES), PAGEREF(InstrPAGEREF), HYPERLINK(InstrHyperlink), Unsupported(String), @@ -21,6 +22,7 @@ impl BuildXML for Box { InstrText::TC(tc) => tc.build(), InstrText::PAGEREF(page_ref) => page_ref.build(), InstrText::PAGE(page) => page.build(), + InstrText::NUMPAGES(page) => page.build(), InstrText::HYPERLINK(_link) => todo!(), InstrText::Unsupported(s) => s.as_bytes().to_vec(), }; @@ -62,6 +64,12 @@ impl Serialize for InstrText { t.serialize_field("data", s)?; t.end() } + InstrText::NUMPAGES(ref s) => { + let mut t = serializer.serialize_struct("NUMPAGES", 2)?; + t.serialize_field("type", "numPages")?; + t.serialize_field("data", s)?; + t.end() + } InstrText::HYPERLINK(ref s) => { let mut t = serializer.serialize_struct("HYPERLINK", 2)?; t.serialize_field("type", "hyperlink")?; diff --git a/docx-core/src/documents/elements/mod.rs b/docx-core/src/documents/elements/mod.rs index 55a75c1..9263ff9 100644 --- a/docx-core/src/documents/elements/mod.rs +++ b/docx-core/src/documents/elements/mod.rs @@ -40,6 +40,7 @@ mod indent; mod indent_level; mod insert; mod instr_hyperlink; +mod instr_num_pages; mod instr_page; mod instr_pageref; mod instr_tc; @@ -59,6 +60,7 @@ mod link; mod mc_fallback; mod name; mod next; +mod num_pages; mod number_format; mod numbering; mod numbering_id; @@ -172,6 +174,7 @@ pub use indent::*; pub use indent_level::*; pub use insert::*; pub use instr_hyperlink::*; +pub use instr_num_pages::*; pub use instr_page::*; pub use instr_pageref::*; pub use instr_tc::*; @@ -191,6 +194,7 @@ pub use link::*; pub use mc_fallback::*; pub use name::*; pub use next::*; +pub use num_pages::*; pub use number_format::*; pub use numbering::*; pub use numbering_id::*; diff --git a/docx-core/src/documents/elements/num_pages.rs b/docx-core/src/documents/elements/num_pages.rs new file mode 100644 index 0000000..e3832ff --- /dev/null +++ b/docx-core/src/documents/elements/num_pages.rs @@ -0,0 +1,66 @@ +use serde::Serialize; + +use crate::documents::*; +use crate::types::*; +use crate::xml_builder::*; + +#[derive(Serialize, Debug, Clone, PartialEq)] +pub struct NumPages { + pub instr: InstrNUMPAGES, +} + +impl Default for NumPages { + fn default() -> Self { + Self { + instr: InstrNUMPAGES {}, + } + } +} + +impl NumPages { + pub fn new() -> Self { + Self::default() + } + + fn inner_build(&self) -> Vec { + let b = XMLBuilder::new(); + let r = Run::new() + .add_field_char(FieldCharType::Begin, false) + .add_instr_text(InstrText::NUMPAGES(self.instr.clone())) + .add_field_char(FieldCharType::Separate, false) + .add_text("1") + .add_field_char(FieldCharType::End, false); + + b.add_child(&r).build() + } +} + +impl BuildXML for NumPages { + fn build(&self) -> Vec { + self.inner_build() + } +} + +impl BuildXML for Box { + fn build(&self) -> Vec { + self.inner_build() + } +} + +#[cfg(test)] +mod tests { + + use super::*; + #[cfg(test)] + use pretty_assertions::assert_eq; + use std::str; + + #[test] + fn test_num_pages() { + let b = NumPages::new().build(); + assert_eq!( + str::from_utf8(&b).unwrap(), + r#"NUMPAGES1"# + ); + } +} diff --git a/docx-core/src/documents/elements/page_num.rs b/docx-core/src/documents/elements/page_num.rs index c24f735..89f69eb 100644 --- a/docx-core/src/documents/elements/page_num.rs +++ b/docx-core/src/documents/elements/page_num.rs @@ -7,18 +7,12 @@ use crate::xml_builder::*; #[derive(Serialize, Debug, Clone, PartialEq)] pub struct PageNum { pub instr: InstrPAGE, - #[serde(skip_serializing_if = "Option::is_none")] - pub frame_property: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub paragraph_property: Option, } impl Default for PageNum { fn default() -> Self { Self { instr: InstrPAGE {}, - frame_property: None, - paragraph_property: None, } } } @@ -28,140 +22,16 @@ impl PageNum { Self::default() } - pub fn wrap(mut self, wrap: impl Into) -> Self { - self.frame_property = Some(FrameProperty { - wrap: Some(wrap.into()), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn v_anchor(mut self, anchor: impl Into) -> Self { - self.frame_property = Some(FrameProperty { - v_anchor: Some(anchor.into()), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn h_anchor(mut self, anchor: impl Into) -> Self { - self.frame_property = Some(FrameProperty { - h_anchor: Some(anchor.into()), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn h_rule(mut self, r: impl Into) -> Self { - self.frame_property = Some(FrameProperty { - h_rule: Some(r.into()), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn x_align(mut self, align: impl Into) -> Self { - self.frame_property = Some(FrameProperty { - x_align: Some(align.into()), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn y_align(mut self, align: impl Into) -> Self { - self.frame_property = Some(FrameProperty { - y_align: Some(align.into()), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn h_space(mut self, x: i32) -> Self { - self.frame_property = Some(FrameProperty { - h_space: Some(x), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn v_space(mut self, x: i32) -> Self { - self.frame_property = Some(FrameProperty { - v_space: Some(x), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn x(mut self, x: i32) -> Self { - self.frame_property = Some(FrameProperty { - x: Some(x), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn y(mut self, y: i32) -> Self { - self.frame_property = Some(FrameProperty { - y: Some(y), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn width(mut self, n: u32) -> Self { - self.frame_property = Some(FrameProperty { - w: Some(n), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn height(mut self, n: u32) -> Self { - self.frame_property = Some(FrameProperty { - h: Some(n), - ..self.frame_property.unwrap_or_default() - }); - self - } - - pub fn align(mut self, alignment_type: AlignmentType) -> Self { - self.paragraph_property = Some( - self.paragraph_property - .unwrap_or_default() - .align(alignment_type), - ); - self - } - fn inner_build(&self) -> Vec { - let p = StructuredDataTagProperty::new(); - let mut b = XMLBuilder::new(); + let b = XMLBuilder::new(); + let r = Run::new() + .add_field_char(FieldCharType::Begin, false) + .add_instr_text(InstrText::PAGE(self.instr.clone())) + .add_field_char(FieldCharType::Separate, false) + .add_text("1") + .add_field_char(FieldCharType::End, false); - b = b - .open_structured_tag() - .add_child(&p) - .open_structured_tag_content(); - - let mut p = Paragraph::new().add_run( - Run::new() - .add_field_char(FieldCharType::Begin, false) - .add_instr_text(InstrText::PAGE(self.instr.clone())) - .add_field_char(FieldCharType::Separate, false) - .add_text("1") - .add_field_char(FieldCharType::End, false), - ); - - if let Some(ref pr) = self.paragraph_property { - p.property = pr.clone(); - } - - if let Some(ref f) = self.frame_property { - p.property.frame_property = Some(f.clone()); - } - - b = b.add_child(&p); - b = b.close().close(); - b.build() + b.add_child(&r).build() } } @@ -190,18 +60,7 @@ mod tests { let b = PageNum::new().build(); assert_eq!( str::from_utf8(&b).unwrap(), - r#"PAGE1 -"# - ); - } - - #[test] - fn test_page_with_wrap() { - let b = PageNum::new().wrap("none").x_align("left").build(); - assert_eq!( - str::from_utf8(&b).unwrap(), - r#"PAGE1 -"# + r#"PAGE1"# ); } } diff --git a/docx-core/src/documents/elements/paragraph.rs b/docx-core/src/documents/elements/paragraph.rs index 56290a6..00d5b12 100644 --- a/docx-core/src/documents/elements/paragraph.rs +++ b/docx-core/src/documents/elements/paragraph.rs @@ -37,6 +37,8 @@ pub enum ParagraphChild { CommentStart(Box), CommentEnd(CommentRangeEnd), StructuredDataTag(Box), + PageNum(Box), + NumPages(Box), } impl BuildXML for ParagraphChild { @@ -51,6 +53,8 @@ impl BuildXML for ParagraphChild { ParagraphChild::CommentStart(v) => v.build(), ParagraphChild::CommentEnd(v) => v.build(), ParagraphChild::StructuredDataTag(v) => v.build(), + ParagraphChild::PageNum(v) => v.build(), + ParagraphChild::NumPages(v) => v.build(), } } } @@ -115,6 +119,18 @@ impl Serialize for ParagraphChild { t.serialize_field("data", r)?; t.end() } + ParagraphChild::PageNum(ref r) => { + let mut t = serializer.serialize_struct("PageNum", 2)?; + t.serialize_field("type", "pageNum")?; + t.serialize_field("data", r)?; + t.end() + } + ParagraphChild::NumPages(ref r) => { + let mut t = serializer.serialize_struct("NumPages", 2)?; + t.serialize_field("type", "numPages")?; + t.serialize_field("data", r)?; + t.end() + } } } } @@ -357,6 +373,113 @@ impl Paragraph { } s } + + pub fn add_page_num(mut self, p: PageNum) -> Self { + self.children.push(ParagraphChild::PageNum(Box::new(p))); + self + } + + pub fn add_num_pages(mut self, p: NumPages) -> Self { + self.children.push(ParagraphChild::NumPages(Box::new(p))); + self + } + + // frameProperty + pub fn wrap(mut self, wrap: impl Into) -> Self { + self.property.frame_property = Some(FrameProperty { + wrap: Some(wrap.into()), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn v_anchor(mut self, anchor: impl Into) -> Self { + self.property.frame_property = Some(FrameProperty { + v_anchor: Some(anchor.into()), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn h_anchor(mut self, anchor: impl Into) -> Self { + self.property.frame_property = Some(FrameProperty { + h_anchor: Some(anchor.into()), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn h_rule(mut self, r: impl Into) -> Self { + self.property.frame_property = Some(FrameProperty { + h_rule: Some(r.into()), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn x_align(mut self, align: impl Into) -> Self { + self.property.frame_property = Some(FrameProperty { + x_align: Some(align.into()), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn y_align(mut self, align: impl Into) -> Self { + self.property.frame_property = Some(FrameProperty { + y_align: Some(align.into()), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn h_space(mut self, x: i32) -> Self { + self.property.frame_property = Some(FrameProperty { + h_space: Some(x), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn v_space(mut self, x: i32) -> Self { + self.property.frame_property = Some(FrameProperty { + v_space: Some(x), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_x(mut self, x: i32) -> Self { + self.property.frame_property = Some(FrameProperty { + x: Some(x), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_y(mut self, y: i32) -> Self { + self.property.frame_property = Some(FrameProperty { + y: Some(y), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_width(mut self, n: u32) -> Self { + self.property.frame_property = Some(FrameProperty { + w: Some(n), + ..self.property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_height(mut self, n: u32) -> Self { + self.property.frame_property = Some(FrameProperty { + h: Some(n), + ..self.property.frame_property.unwrap_or_default() + }); + self + } } impl BuildXML for Paragraph { diff --git a/docx-core/src/documents/elements/style.rs b/docx-core/src/documents/elements/style.rs index ddfe1d9..8eb53a9 100644 --- a/docx-core/src/documents/elements/style.rs +++ b/docx-core/src/documents/elements/style.rs @@ -215,6 +215,103 @@ impl Style { self.table_cell_property = p; self } + + // frameProperty + pub fn wrap(mut self, wrap: impl Into) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + wrap: Some(wrap.into()), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn v_anchor(mut self, anchor: impl Into) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + v_anchor: Some(anchor.into()), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn h_anchor(mut self, anchor: impl Into) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + h_anchor: Some(anchor.into()), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn h_rule(mut self, r: impl Into) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + h_rule: Some(r.into()), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn x_align(mut self, align: impl Into) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + x_align: Some(align.into()), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn y_align(mut self, align: impl Into) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + y_align: Some(align.into()), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn h_space(mut self, x: i32) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + h_space: Some(x), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn v_space(mut self, x: i32) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + v_space: Some(x), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_x(mut self, x: i32) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + x: Some(x), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_y(mut self, y: i32) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + y: Some(y), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_width(mut self, n: u32) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + w: Some(n), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } + + pub fn frame_height(mut self, n: u32) -> Self { + self.paragraph_property.frame_property = Some(FrameProperty { + h: Some(n), + ..self.paragraph_property.frame_property.unwrap_or_default() + }); + self + } } impl BuildXML for Style { diff --git a/docx-core/src/documents/footer.rs b/docx-core/src/documents/footer.rs index 9f728dc..6c87565 100644 --- a/docx-core/src/documents/footer.rs +++ b/docx-core/src/documents/footer.rs @@ -33,11 +33,6 @@ impl Footer { self } - pub fn add_page_num(mut self, p: PageNum) -> Self { - self.children.push(FooterChild::PageNum(Box::new(p))); - self - } - /// reader only pub(crate) fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Self { if t.has_numbering { @@ -53,7 +48,6 @@ impl Footer { pub enum FooterChild { Paragraph(Box), Table(Box), - PageNum(Box), StructuredDataTag(Box), } @@ -75,12 +69,6 @@ impl Serialize for FooterChild { t.serialize_field("data", c)?; t.end() } - FooterChild::PageNum(ref r) => { - let mut t = serializer.serialize_struct("PageNum", 2)?; - t.serialize_field("type", "pageNum")?; - t.serialize_field("data", r)?; - t.end() - } FooterChild::StructuredDataTag(ref r) => { let mut t = serializer.serialize_struct("StructuredDataTag", 2)?; t.serialize_field("type", "structuredDataTag")?; @@ -100,7 +88,6 @@ impl BuildXML for Footer { match c { FooterChild::Paragraph(p) => b = b.add_child(p), FooterChild::Table(t) => b = b.add_child(t), - FooterChild::PageNum(p) => b = b.add_child(p), FooterChild::StructuredDataTag(t) => b = b.add_child(t), } } diff --git a/docx-core/src/documents/header.rs b/docx-core/src/documents/header.rs index 92fbffc..8df882b 100644 --- a/docx-core/src/documents/header.rs +++ b/docx-core/src/documents/header.rs @@ -33,11 +33,6 @@ impl Header { self } - pub fn add_page_num(mut self, p: PageNum) -> Self { - self.children.push(HeaderChild::PageNum(Box::new(p))); - self - } - /// reader only pub(crate) fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Self { if t.has_numbering { @@ -53,7 +48,6 @@ impl Header { pub enum HeaderChild { Paragraph(Box), Table(Box
), - PageNum(Box), StructuredDataTag(Box), } @@ -75,12 +69,6 @@ impl Serialize for HeaderChild { t.serialize_field("data", c)?; t.end() } - HeaderChild::PageNum(ref r) => { - let mut t = serializer.serialize_struct("PageNum", 2)?; - t.serialize_field("type", "pageNum")?; - t.serialize_field("data", r)?; - t.end() - } HeaderChild::StructuredDataTag(ref r) => { let mut t = serializer.serialize_struct("StructuredDataTag", 2)?; t.serialize_field("type", "structuredDataTag")?; @@ -100,7 +88,6 @@ impl BuildXML for Header { match c { HeaderChild::Paragraph(p) => b = b.add_child(p), HeaderChild::Table(t) => b = b.add_child(t), - HeaderChild::PageNum(p) => b = b.add_child(p), HeaderChild::StructuredDataTag(t) => b = b.add_child(t), } } diff --git a/docx-core/src/documents/mod.rs b/docx-core/src/documents/mod.rs index 01813bd..38e17a8 100644 --- a/docx-core/src/documents/mod.rs +++ b/docx-core/src/documents/mod.rs @@ -925,7 +925,6 @@ impl Docx { Some("header"), ); } - HeaderChild::PageNum(_) => {} HeaderChild::StructuredDataTag(tag) => { for child in tag.children.iter_mut() { if let StructuredDataTagChild::Paragraph(paragraph) = child { @@ -971,7 +970,6 @@ impl Docx { Some("header"), ); } - HeaderChild::PageNum(_) => {} HeaderChild::StructuredDataTag(tag) => { for child in tag.children.iter_mut() { if let StructuredDataTagChild::Paragraph(paragraph) = child { @@ -1017,7 +1015,6 @@ impl Docx { Some("header"), ); } - HeaderChild::PageNum(_) => {} HeaderChild::StructuredDataTag(tag) => { for child in tag.children.iter_mut() { if let StructuredDataTagChild::Paragraph(paragraph) = child { @@ -1062,7 +1059,6 @@ impl Docx { Some("footer"), ); } - FooterChild::PageNum(_) => {} FooterChild::Table(table) => { collect_images_from_table( table, @@ -1108,7 +1104,6 @@ impl Docx { Some("footer"), ); } - FooterChild::PageNum(_) => {} FooterChild::Table(table) => { collect_images_from_table( table, @@ -1154,7 +1149,6 @@ impl Docx { Some("footer"), ); } - FooterChild::PageNum(_) => {} FooterChild::Table(table) => { collect_images_from_table( table, diff --git a/docx-wasm/js/builder.ts b/docx-wasm/js/builder.ts index 14dfb99..618f79b 100644 --- a/docx-wasm/js/builder.ts +++ b/docx-wasm/js/builder.ts @@ -11,6 +11,8 @@ import { Hyperlink, convertHyperlinkType } from "./hyperlink"; import { setParagraphProperty } from "./paragraph-property"; import * as wasm from "./pkg"; +import { PageNum } from "./page-num"; +import { NumPages } from "./num-pages"; type Child = Paragraph | Table | Comment | Hyperlink; @@ -64,6 +66,10 @@ function buildParagraph(child: Paragraph) { paragraph = paragraph.add_comment_start(comment as wasm.Comment); } else if (child instanceof CommentEnd) { paragraph = paragraph.add_comment_end(child.id); + } else if (child instanceof PageNum) { + paragraph = paragraph.add_page_num(wasm.createPageNum()); + } else if (child instanceof NumPages) { + paragraph = paragraph.add_num_pages(wasm.createNumPages()); } }); diff --git a/docx-wasm/js/footer.ts b/docx-wasm/js/footer.ts index a7a44df..1c58839 100644 --- a/docx-wasm/js/footer.ts +++ b/docx-wasm/js/footer.ts @@ -1,10 +1,9 @@ -import { PageNum } from "./page-num"; import { Paragraph } from "./paragraph"; import { Table } from "./table"; export class Footer { hasNumberings = false; - children: (Paragraph | Table | PageNum)[] = []; + children: (Paragraph | Table)[] = []; addParagraph(p: Paragraph) { if (p.hasNumberings) { @@ -21,9 +20,4 @@ export class Footer { this.children.push(t); return this; } - - addPageNum(p: PageNum) { - this.children.push(p); - return this; - } } diff --git a/docx-wasm/js/header.ts b/docx-wasm/js/header.ts index bd416e5..da2d614 100644 --- a/docx-wasm/js/header.ts +++ b/docx-wasm/js/header.ts @@ -1,10 +1,9 @@ -import { PageNum } from "./page-num"; import { Paragraph } from "./paragraph"; import { Table } from "./table"; export class Header { hasNumberings = false; - children: (Paragraph | Table | PageNum)[] = []; + children: (Paragraph | Table)[] = []; addParagraph(p: Paragraph) { if (p.hasNumberings) { @@ -21,9 +20,4 @@ export class Header { this.children.push(t); return this; } - - addPageNum(p: PageNum) { - this.children.push(p); - return this; - } } diff --git a/docx-wasm/js/index.ts b/docx-wasm/js/index.ts index f3fa7d6..0192ddf 100644 --- a/docx-wasm/js/index.ts +++ b/docx-wasm/js/index.ts @@ -424,9 +424,6 @@ export class Docx { header = header.add_paragraph(build(c)); } else if (c instanceof Table) { header = header.add_table(c.build()); - } else { - const p = c.build(); - header = header.add_page_num(p); } }); docx = docx.header(header); @@ -439,9 +436,6 @@ export class Docx { header = header.add_paragraph(build(c)); } else if (c instanceof Table) { header = header.add_table(c.build()); - } else { - const p = c.build(); - header = header.add_page_num(p); } }); docx = docx.first_header(header); @@ -454,9 +448,6 @@ export class Docx { header = header.add_paragraph(build(c)); } else if (c instanceof Table) { header = header.add_table(c.build()); - } else { - const p = c.build(); - header = header.add_page_num(p); } }); docx = docx.even_header(header); @@ -469,9 +460,6 @@ export class Docx { footer = footer.add_paragraph(build(c)); } else if (c instanceof Table) { footer = footer.add_table(c.build()); - } else { - const p = c.build(); - footer = footer.add_page_num(p); } }); docx = docx.footer(footer); @@ -484,9 +472,6 @@ export class Docx { footer = footer.add_paragraph(build(c)); } else if (c instanceof Table) { footer = footer.add_table(c.build()); - } else { - const p = c.build(); - footer = footer.add_page_num(p); } }); docx = docx.first_footer(footer); @@ -499,9 +484,6 @@ export class Docx { footer = footer.add_paragraph(build(c)); } else if (c instanceof Table) { footer = footer.add_table(c.build()); - } else { - const p = c.build(); - footer = footer.add_page_num(p); } }); docx = docx.even_footer(footer); @@ -687,5 +669,6 @@ export * from "./json"; export * from "./webextension"; export * from "./header"; export * from "./page-num"; +export * from "./num-pages"; export * from "./footer"; export * from "./image"; diff --git a/docx-wasm/js/num-pages.ts b/docx-wasm/js/num-pages.ts new file mode 100644 index 0000000..e2a8e57 --- /dev/null +++ b/docx-wasm/js/num-pages.ts @@ -0,0 +1,7 @@ +import * as wasm from "./pkg/docx_wasm"; + +export class NumPages { + build() { + return wasm.createNumPages(); + } +} diff --git a/docx-wasm/js/page-num.ts b/docx-wasm/js/page-num.ts index cc494bb..5535f68 100644 --- a/docx-wasm/js/page-num.ts +++ b/docx-wasm/js/page-num.ts @@ -1,153 +1,8 @@ -import { - AlignmentType, - ParagraphProperty, - createDefaultParagraphProperty, - createParagraphAlignment, -} from "./paragraph-property"; import * as wasm from "./pkg/docx_wasm"; -export type FrameProperty = { - h?: number; - hRule?: string; - hAnchor?: string; - hSpace?: number; - vAnchor?: string; - vSpace?: number; - w?: number; - wrap?: string; - x?: number; - xAlign?: string; - y?: number; - yAlign?: string; -}; - export class PageNum { - frameProperty: FrameProperty | null = null; - paragraphProperty: ParagraphProperty | null = null; - - height(h: number) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.h = h; - return this; - } - hRule(r: string) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.hRule = r; - return this; - } - - hAnchor(a: string) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.hAnchor = a; - return this; - } - - hSpace(s: number) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.hSpace = s; - return this; - } - - vAnchor(a: string) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.vAnchor = a; - return this; - } - - vSpace(s: number) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.vSpace = s; - return this; - } - - width(w: number) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.w = w; - return this; - } - - wrap(w: string) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.wrap = w; - return this; - } - - x(x: number) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.x = x; - return this; - } - - xAlign(a: string) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.xAlign = a; - return this; - } - - y(y: number) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.y = y; - return this; - } - - yAlign(y: string) { - this.frameProperty = { ...this.frameProperty }; - this.frameProperty.yAlign = y; - return this; - } - - align(align: AlignmentType) { - this.paragraphProperty = { - ...createDefaultParagraphProperty(), - align, - }; - return this; - } - build() { - let pageNum = wasm.createPageNum(); - if (this.frameProperty?.h != null) { - pageNum = pageNum.height(this.frameProperty.h); - } - if (this.frameProperty?.hRule != null) { - pageNum = pageNum.h_rule(this.frameProperty.hRule); - } - if (this.frameProperty?.hAnchor != null) { - pageNum = pageNum.h_anchor(this.frameProperty.hAnchor); - } - if (this.frameProperty?.hSpace != null) { - pageNum = pageNum.h_space(this.frameProperty.hSpace); - } - if (this.frameProperty?.vAnchor != null) { - pageNum = pageNum.v_anchor(this.frameProperty.vAnchor); - } - if (this.frameProperty?.vSpace != null) { - pageNum = pageNum.v_space(this.frameProperty.vSpace); - } - if (this.frameProperty?.w != null) { - pageNum = pageNum.width(this.frameProperty.w); - } - if (this.frameProperty?.wrap != null) { - pageNum = pageNum.wrap(this.frameProperty.wrap); - } - if (this.frameProperty?.x != null) { - pageNum = pageNum.x(this.frameProperty.x); - } - if (this.frameProperty?.xAlign != null) { - pageNum = pageNum.x_align(this.frameProperty.xAlign); - } - if (this.frameProperty?.y != null) { - pageNum = pageNum.y(this.frameProperty.y); - } - if (this.frameProperty?.yAlign != null) { - pageNum = pageNum.y_align(this.frameProperty.yAlign); - } - if (this.paragraphProperty?.align != null) { - const align = createParagraphAlignment(this.paragraphProperty.align); - if (align) { - pageNum = pageNum.align(align); - } - } + const pageNum = wasm.createPageNum(); return pageNum; } } diff --git a/docx-wasm/js/paragraph-property.ts b/docx-wasm/js/paragraph-property.ts index 095f609..d24aa92 100644 --- a/docx-wasm/js/paragraph-property.ts +++ b/docx-wasm/js/paragraph-property.ts @@ -11,6 +11,21 @@ export type SpecialIndentKind = "firstLine" | "hanging"; export type LineSpacingType = "atLeast" | "auto" | "exact"; +export type FrameProperty = { + h?: number; + hRule?: string; + hAnchor?: string; + hSpace?: number; + vAnchor?: string; + vSpace?: number; + w?: number; + wrap?: string; + x?: number; + xAlign?: string; + y?: number; + yAlign?: string; +}; + export class LineSpacing { _before?: number; _after?: number; @@ -69,6 +84,7 @@ export type ParagraphProperty = { outlineLvl?: number | null; adjustRightInd?: number; tabs?: Tab[]; + frameProperty?: FrameProperty; }; export const createDefaultParagraphProperty = (): ParagraphProperty => { @@ -395,5 +411,44 @@ export const setParagraphProperty = ( } } + if (property.frameProperty) { + if (property.frameProperty?.h != null) { + target = target.frame_height(property.frameProperty.h) as T; + } + if (property.frameProperty?.hRule != null) { + target = target.h_rule(property.frameProperty.hRule) as T; + } + if (property.frameProperty?.hAnchor != null) { + target = target.h_anchor(property.frameProperty.hAnchor) as T; + } + if (property.frameProperty?.hSpace != null) { + target = target.h_space(property.frameProperty.hSpace) as T; + } + if (property.frameProperty?.vAnchor != null) { + target = target.v_anchor(property.frameProperty.vAnchor) as T; + } + if (property.frameProperty?.vSpace != null) { + target = target.v_space(property.frameProperty.vSpace) as T; + } + if (property.frameProperty?.w != null) { + target = target.frame_width(property.frameProperty.w) as T; + } + if (property.frameProperty?.wrap != null) { + target = target.wrap(property.frameProperty.wrap) as T; + } + if (property.frameProperty?.x != null) { + target = target.frame_x(property.frameProperty.x) as T; + } + if (property.frameProperty?.xAlign != null) { + target = target.x_align(property.frameProperty.xAlign) as T; + } + if (property.frameProperty?.y != null) { + target = target.frame_y(property.frameProperty.y) as T; + } + if (property.frameProperty?.yAlign != null) { + target = target.y_align(property.frameProperty.yAlign) as T; + } + } + return target; }; diff --git a/docx-wasm/js/paragraph.ts b/docx-wasm/js/paragraph.ts index 295adab..387b9ad 100644 --- a/docx-wasm/js/paragraph.ts +++ b/docx-wasm/js/paragraph.ts @@ -17,6 +17,8 @@ import { Hyperlink } from "./hyperlink"; import { TextAlignmentType } from "./json/bindings/TextAlignmentType"; import { TabValueType } from "./json/bindings/TabValueType"; import { TabLeaderType } from "./json/bindings/TabLeaderType"; +import { NumPages } from "./num-pages"; +import { PageNum } from "./page-num"; export type ParagraphChild = | Run @@ -26,7 +28,9 @@ export type ParagraphChild = | BookmarkStart | BookmarkEnd | Comment - | CommentEnd; + | CommentEnd + | NumPages + | PageNum; export class Paragraph { hasNumberings = false; @@ -73,6 +77,16 @@ export class Paragraph { return this; } + addPageNum() { + this.children.push(new PageNum()); + return this; + } + + addNumPages() { + this.children.push(new NumPages()); + return this; + } + tabs( tabs: { val: TabValueType | null; @@ -195,4 +209,76 @@ export class Paragraph { this.property.paragraphPropertyChange = propertyChange; return this; } + + // frameProperty + frameHeight(h: number) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.h = h; + return this; + } + hRule(r: string) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.hRule = r; + return this; + } + + hAnchor(a: string) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.hAnchor = a; + return this; + } + + hSpace(s: number) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.hSpace = s; + return this; + } + + vAnchor(a: string) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.vAnchor = a; + return this; + } + + vSpace(s: number) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.vSpace = s; + return this; + } + + frameWidth(w: number) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.w = w; + return this; + } + + wrap(w: string) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.wrap = w; + return this; + } + + frameX(x: number) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.x = x; + return this; + } + + xAlign(a: string) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.xAlign = a; + return this; + } + + frameY(y: number) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.y = y; + return this; + } + + yAlign(y: string) { + this.property.frameProperty = { ...this.property.frameProperty }; + this.property.frameProperty.yAlign = y; + return this; + } } diff --git a/docx-wasm/package.json b/docx-wasm/package.json index 2642779..61e4ca7 100644 --- a/docx-wasm/package.json +++ b/docx-wasm/package.json @@ -1,6 +1,6 @@ { "name": "docx-wasm", - "version": "0.4.17", + "version": "0.4.18-rc2", "main": "dist/node/index.js", "browser": "dist/web/index.js", "author": "bokuweb ", diff --git a/docx-wasm/src/footer.rs b/docx-wasm/src/footer.rs index 623265b..5e4fef6 100644 --- a/docx-wasm/src/footer.rs +++ b/docx-wasm/src/footer.rs @@ -27,9 +27,4 @@ impl Footer { self.0 = self.0.add_table(t.take()); self } - - pub fn add_page_num(mut self, t: PageNum) -> Self { - self.0 = self.0.add_page_num(t.take()); - self - } } diff --git a/docx-wasm/src/header.rs b/docx-wasm/src/header.rs index ff3dda4..940600c 100644 --- a/docx-wasm/src/header.rs +++ b/docx-wasm/src/header.rs @@ -27,9 +27,4 @@ impl Header { self.0 = self.0.add_table(t.take()); self } - - pub fn add_page_num(mut self, t: PageNum) -> Self { - self.0 = self.0.add_page_num(t.take()); - self - } } diff --git a/docx-wasm/src/lib.rs b/docx-wasm/src/lib.rs index 5fe442b..1660a7e 100644 --- a/docx-wasm/src/lib.rs +++ b/docx-wasm/src/lib.rs @@ -10,6 +10,7 @@ mod insert; mod level; mod level_override; mod line_spacing; +mod num_pages; mod numbering; mod page_margin; mod page_num; @@ -41,6 +42,7 @@ pub use insert::*; pub use level::*; pub use level_override::*; pub use line_spacing::*; +pub use num_pages::*; pub use numbering::*; pub use page_margin::*; pub use page_num::*; diff --git a/docx-wasm/src/num_pages.rs b/docx-wasm/src/num_pages.rs new file mode 100644 index 0000000..88bd90e --- /dev/null +++ b/docx-wasm/src/num_pages.rs @@ -0,0 +1,16 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[derive(Debug)] +pub struct NumPages(docx_rs::NumPages); + +#[wasm_bindgen(js_name = createNumPages)] +pub fn create_num_pages() -> NumPages { + NumPages(docx_rs::NumPages::new()) +} + +impl NumPages { + pub fn take(self) -> docx_rs::NumPages { + self.0 + } +} diff --git a/docx-wasm/src/page_num.rs b/docx-wasm/src/page_num.rs index 8698628..3ecb7ff 100644 --- a/docx-wasm/src/page_num.rs +++ b/docx-wasm/src/page_num.rs @@ -14,77 +14,3 @@ impl PageNum { self.0 } } - -#[wasm_bindgen] -impl PageNum { - pub fn wrap(mut self, wrap: &str) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().wrap(wrap)); - self - } - - pub fn v_anchor(mut self, anchor: &str) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().v_anchor(anchor)); - self - } - - pub fn h_anchor(mut self, anchor: &str) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().h_anchor(anchor)); - self - } - - pub fn h_rule(mut self, r: &str) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().h_rule(r)); - self - } - - pub fn x_align(mut self, align: &str) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().x_align(align)); - self - } - - pub fn y_align(mut self, align: &str) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().y_align(align)); - self - } - - pub fn h_space(mut self, x: i32) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().h_space(x)); - self - } - - pub fn v_space(mut self, x: i32) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().v_space(x)); - self - } - - pub fn x(mut self, x: i32) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().x(x)); - self - } - - pub fn y(mut self, y: i32) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().y(y)); - self - } - - pub fn width(mut self, n: u32) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().width(n)); - self - } - - pub fn height(mut self, n: u32) -> Self { - self.0.frame_property = Some(self.0.frame_property.unwrap_or_default().height(n)); - self - } - - // TODO: add other pPr fields - pub fn align(mut self, alignment_type: docx_rs::AlignmentType) -> Self { - self.0.paragraph_property = Some( - self.0 - .paragraph_property - .unwrap_or_default() - .align(alignment_type), - ); - self - } -} diff --git a/docx-wasm/src/paragraph.rs b/docx-wasm/src/paragraph.rs index 6c091d6..426f3d6 100644 --- a/docx-wasm/src/paragraph.rs +++ b/docx-wasm/src/paragraph.rs @@ -247,6 +247,77 @@ impl Paragraph { self.0.property = self.0.property.paragraph_property_change(p.take()); self } + + pub fn add_page_num(mut self, p: PageNum) -> Self { + self.0 = self.0.add_page_num(p.take()); + self + } + + pub fn add_num_pages(mut self, p: NumPages) -> Self { + self.0 = self.0.add_num_pages(p.take()); + self + } + + // frame property + pub fn wrap(mut self, wrap: &str) -> Self { + self.0 = self.0.wrap(wrap); + self + } + + pub fn v_anchor(mut self, anchor: &str) -> Self { + self.0 = self.0.v_anchor(anchor); + self + } + + pub fn h_anchor(mut self, anchor: &str) -> Self { + self.0 = self.0.h_anchor(anchor); + self + } + + pub fn h_rule(mut self, r: &str) -> Self { + self.0 = self.0.h_rule(r); + self + } + + pub fn x_align(mut self, align: &str) -> Self { + self.0 = self.0.x_align(align); + self + } + + pub fn y_align(mut self, align: &str) -> Self { + self.0 = self.0.y_align(align); + self + } + + pub fn h_space(mut self, x: i32) -> Self { + self.0 = self.0.h_space(x); + self + } + + pub fn v_space(mut self, x: i32) -> Self { + self.0 = self.0.v_space(x); + self + } + + pub fn frame_x(mut self, x: i32) -> Self { + self.0 = self.0.frame_x(x); + self + } + + pub fn frame_y(mut self, y: i32) -> Self { + self.0 = self.0.frame_y(y); + self + } + + pub fn frame_width(mut self, n: u32) -> Self { + self.0 = self.0.frame_width(n); + self + } + + pub fn frame_height(mut self, n: u32) -> Self { + self.0 = self.0.frame_height(n); + self + } } impl Paragraph { diff --git a/docx-wasm/src/style.rs b/docx-wasm/src/style.rs index f28362b..199893e 100644 --- a/docx-wasm/src/style.rs +++ b/docx-wasm/src/style.rs @@ -245,6 +245,67 @@ impl Style { self.0.table_property = self.0.table_property.layout(t); self } + + // frame property + pub fn wrap(mut self, wrap: &str) -> Self { + self.0 = self.0.wrap(wrap); + self + } + + pub fn v_anchor(mut self, anchor: &str) -> Self { + self.0 = self.0.v_anchor(anchor); + self + } + + pub fn h_anchor(mut self, anchor: &str) -> Self { + self.0 = self.0.h_anchor(anchor); + self + } + + pub fn h_rule(mut self, r: &str) -> Self { + self.0 = self.0.h_rule(r); + self + } + + pub fn x_align(mut self, align: &str) -> Self { + self.0 = self.0.x_align(align); + self + } + + pub fn y_align(mut self, align: &str) -> Self { + self.0 = self.0.y_align(align); + self + } + + pub fn h_space(mut self, x: i32) -> Self { + self.0 = self.0.h_space(x); + self + } + + pub fn v_space(mut self, x: i32) -> Self { + self.0 = self.0.v_space(x); + self + } + + pub fn frame_x(mut self, x: i32) -> Self { + self.0 = self.0.frame_x(x); + self + } + + pub fn frame_y(mut self, y: i32) -> Self { + self.0 = self.0.frame_y(y); + self + } + + pub fn frame_width(mut self, n: u32) -> Self { + self.0 = self.0.frame_width(n); + self + } + + pub fn frame_height(mut self, n: u32) -> Self { + self.0 = self.0.frame_height(n); + self + } } impl Style { diff --git a/docx-wasm/test/__snapshots__/index.test.js.snap b/docx-wasm/test/__snapshots__/index.test.js.snap index 37262b9..0c7b0e4 100644 --- a/docx-wasm/test/__snapshots__/index.test.js.snap +++ b/docx-wasm/test/__snapshots__/index.test.js.snap @@ -171637,10 +171637,20 @@ exports[`writer should write pageNum in header 1`] = ` exports[`writer should write pageNum in header 2`] = ` " - Hello world!! + Hello world!! PAGE1 / NUMPAGES1 " `; +exports[`writer should write pageNum in header 3`] = ` +" +Hello world!! PAGE1 / NUMPAGES1" +`; + +exports[`writer should write pageNum in header 4`] = ` +" +" +`; + exports[`writer should write paragraph delete 1`] = ` " diff --git a/docx-wasm/test/index.test.js b/docx-wasm/test/index.test.js index 8c71923..cc3cc5d 100644 --- a/docx-wasm/test/index.test.js +++ b/docx-wasm/test/index.test.js @@ -1045,16 +1045,20 @@ describe("writer", () => { }); test("should write pageNum in header", () => { - const p = new w.Paragraph().addRun(new w.Run().addText("Hello world!!")); - const page = new w.PageNum().align('center'); - const header = new w.Header().addParagraph(p).addPageNum(page); + const p = new w.Paragraph() + .addRun(new w.Run().addText("Hello world!! ")) + .addPageNum() + .addRun(new w.Run().addText(" / ")) + .addNumPages() + .align("center"); + const header = new w.Header().addParagraph(p); const buffer = new w.Docx().header(header).addParagraph(p).build(); writeFileSync("../output/js/header_in_page_num.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { - if (e.entryName.match(/document.xml/)) { + if (e.entryName.match(/document.xml|header/)) { expect(z.readAsText(e)).toMatchSnapshot(); } }