Support frame pr (#687)
* feat: define framePr * fix: read frame pr * fix: page num writer * fix: page num writer * feat: add page num for writer * fix: add page_num for footer * spec: update snaps * fix: clippy * 0.4.12-beta3 * fix: add frameProperty * fixmain
parent
9fbd323ce7
commit
6955cd0e65
|
@ -0,0 +1,22 @@
|
|||
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")));
|
||||
Docx::new()
|
||||
.header(header)
|
||||
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("World")))
|
||||
.build()
|
||||
.pack(file)?;
|
||||
Ok(())
|
||||
}
|
|
@ -4,7 +4,7 @@ use std::fs::File;
|
|||
use std::io::{Read, Write};
|
||||
|
||||
pub fn main() {
|
||||
let mut file = File::open("./header-image.docx").unwrap();
|
||||
let mut file = File::open("./hello.docx").unwrap();
|
||||
let mut buf = vec![];
|
||||
file.read_to_end(&mut buf).unwrap();
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::documents::BuildXML;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.frameproperties?view=openxml-3.0.1
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "wasm", derive(ts_rs::TS))]
|
||||
#[cfg_attr(feature = "wasm", ts(export))]
|
||||
pub struct FrameProperty {
|
||||
/// Frame Height
|
||||
/// Represents the following attribute in the schema: w:h
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub h: Option<u32>,
|
||||
/// Frame Height Type
|
||||
/// Represents the following attribute in the schema: w:hRule
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub h_rule: Option<String>,
|
||||
/// Frame Horizontal Positioning Base
|
||||
/// Represents the following attribute in the schema: w:hAnchor
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub h_anchor: Option<String>,
|
||||
/// Horizontal Frame Padding
|
||||
/// Represents the following attribute in the schema: w:hSpace
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub h_space: Option<i32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub v_anchor: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub v_space: Option<i32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub w: Option<u32>,
|
||||
/// Text Wrapping Around Frame
|
||||
/// Represents the following attribute in the schema: w:wrap
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wrap: Option<String>,
|
||||
/// Absolute Horizontal Position
|
||||
/// Represents the following attribute in the schema: w:x
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub x: Option<i32>,
|
||||
/// Relative Horizontal Position
|
||||
/// Represents the following attribute in the schema: w:xAlign
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub x_align: Option<String>,
|
||||
/// Absolute Vertical Position
|
||||
/// Represents the following attribute in the schema: w:y
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub y: Option<i32>,
|
||||
/// Relative Vertical Position
|
||||
/// Represents the following attribute in the schema: w:yAlign
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub y_align: Option<String>,
|
||||
}
|
||||
|
||||
impl FrameProperty {
|
||||
pub fn new() -> FrameProperty {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn wrap(mut self, wrap: impl Into<String>) -> Self {
|
||||
self.wrap = Some(wrap.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn v_anchor(mut self, anchor: impl Into<String>) -> Self {
|
||||
self.v_anchor = Some(anchor.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn h_anchor(mut self, anchor: impl Into<String>) -> Self {
|
||||
self.h_anchor = Some(anchor.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn h_rule(mut self, r: impl Into<String>) -> Self {
|
||||
self.h_rule = Some(r.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn x_align(mut self, align: impl Into<String>) -> Self {
|
||||
self.x_align = Some(align.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn y_align(mut self, align: impl Into<String>) -> Self {
|
||||
self.y_align = Some(align.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn h_space(mut self, x: i32) -> Self {
|
||||
self.h_space = Some(x);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn v_space(mut self, x: i32) -> Self {
|
||||
self.v_space = Some(x);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn x(mut self, x: i32) -> Self {
|
||||
self.x = Some(x);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn y(mut self, y: i32) -> Self {
|
||||
self.y = Some(y);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn width(mut self, n: u32) -> Self {
|
||||
self.w = Some(n);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn height(mut self, n: u32) -> Self {
|
||||
self.h = Some(n);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for FrameProperty {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
b.frame_property(self).build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_q_format() {
|
||||
let c = FrameProperty::new().wrap("none");
|
||||
let b = c.build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:framePr w:wrap="none" />"#
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::documents::*;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstrPAGE {}
|
||||
|
||||
impl InstrPAGE {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for InstrPAGE {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let instr = "PAGE".to_owned();
|
||||
instr.into()
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use crate::xml_builder::*;
|
|||
pub enum InstrText {
|
||||
TOC(InstrToC),
|
||||
TC(InstrTC),
|
||||
PAGE(InstrPAGE),
|
||||
PAGEREF(InstrPAGEREF),
|
||||
HYPERLINK(InstrHyperlink),
|
||||
Unsupported(String),
|
||||
|
@ -19,6 +20,7 @@ impl BuildXML for Box<InstrText> {
|
|||
InstrText::TOC(toc) => toc.build(),
|
||||
InstrText::TC(tc) => tc.build(),
|
||||
InstrText::PAGEREF(page_ref) => page_ref.build(),
|
||||
InstrText::PAGE(page) => page.build(),
|
||||
InstrText::HYPERLINK(_link) => todo!(),
|
||||
InstrText::Unsupported(s) => s.as_bytes().to_vec(),
|
||||
};
|
||||
|
@ -54,6 +56,12 @@ impl Serialize for InstrText {
|
|||
t.serialize_field("data", s)?;
|
||||
t.end()
|
||||
}
|
||||
InstrText::PAGE(ref s) => {
|
||||
let mut t = serializer.serialize_struct("PAGE", 2)?;
|
||||
t.serialize_field("type", "page")?;
|
||||
t.serialize_field("data", s)?;
|
||||
t.end()
|
||||
}
|
||||
InstrText::HYPERLINK(ref s) => {
|
||||
let mut t = serializer.serialize_struct("HYPERLINK", 2)?;
|
||||
t.serialize_field("type", "hyperlink")?;
|
||||
|
|
|
@ -29,6 +29,7 @@ mod fld_char;
|
|||
mod font;
|
||||
mod font_scheme;
|
||||
mod footer_reference;
|
||||
mod frame_property;
|
||||
mod grid_span;
|
||||
mod header_reference;
|
||||
mod highlight;
|
||||
|
@ -37,6 +38,7 @@ mod indent;
|
|||
mod indent_level;
|
||||
mod insert;
|
||||
mod instr_hyperlink;
|
||||
mod instr_page;
|
||||
mod instr_pageref;
|
||||
mod instr_tc;
|
||||
mod instr_text;
|
||||
|
@ -61,6 +63,7 @@ mod numbering_id;
|
|||
mod numbering_property;
|
||||
mod outline_lvl;
|
||||
mod page_margin;
|
||||
mod page_num;
|
||||
mod page_num_type;
|
||||
mod page_size;
|
||||
mod paragraph;
|
||||
|
@ -154,6 +157,7 @@ pub use fld_char::*;
|
|||
pub use font::*;
|
||||
pub use font_scheme::*;
|
||||
pub use footer_reference::*;
|
||||
pub use frame_property::*;
|
||||
pub use grid_span::*;
|
||||
pub use header_reference::*;
|
||||
pub use highlight::*;
|
||||
|
@ -162,6 +166,7 @@ pub use indent::*;
|
|||
pub use indent_level::*;
|
||||
pub use insert::*;
|
||||
pub use instr_hyperlink::*;
|
||||
pub use instr_page::*;
|
||||
pub use instr_pageref::*;
|
||||
pub use instr_tc::*;
|
||||
pub use instr_text::*;
|
||||
|
@ -186,6 +191,7 @@ pub use numbering_id::*;
|
|||
pub use numbering_property::*;
|
||||
pub use outline_lvl::*;
|
||||
pub use page_margin::*;
|
||||
pub use page_num::*;
|
||||
pub use page_num_type::*;
|
||||
pub use page_size::*;
|
||||
pub use paragraph::*;
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::documents::*;
|
||||
use crate::types::*;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||
pub struct PageNum {
|
||||
pub instr: InstrPAGE,
|
||||
pub frame_property: Option<FrameProperty>,
|
||||
}
|
||||
|
||||
impl Default for PageNum {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
instr: InstrPAGE {},
|
||||
frame_property: Some(FrameProperty {
|
||||
wrap: Some("none".to_owned()),
|
||||
v_anchor: Some("text".to_owned()),
|
||||
h_anchor: Some("margin".to_owned()),
|
||||
x_align: Some("right".to_owned()),
|
||||
y: Some(1),
|
||||
..Default::default()
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PageNum {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn wrap(mut self, wrap: impl Into<String>) -> 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<String>) -> 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<String>) -> 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<String>) -> 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<String>) -> 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<String>) -> 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
|
||||
}
|
||||
|
||||
fn inner_build(&self) -> Vec<u8> {
|
||||
let p = StructuredDataTagProperty::new();
|
||||
let mut b = XMLBuilder::new();
|
||||
|
||||
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 f) = self.frame_property {
|
||||
p.property.frame_property = Some(f.clone());
|
||||
}
|
||||
|
||||
b = b.add_child(&p);
|
||||
b = b.close().close();
|
||||
b.build()
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for PageNum {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
self.inner_build()
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Box<PageNum> {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
self.inner_build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_page() {
|
||||
let b = PageNum::new().build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:sdt><w:sdtPr><w:rPr /></w:sdtPr><w:sdtContent><w:p w14:paraId="12345678"><w:pPr><w:rPr /><w:framePr w:wrap="none" w:hAnchor="margin" w:vAnchor="text" w:xAlign="right" w:y="1" /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType="begin" w:dirty="false" /><w:instrText>PAGE</w:instrText><w:fldChar w:fldCharType="separate" w:dirty="false" /><w:t xml:space="preserve">1</w:t><w:fldChar w:fldCharType="end" w:dirty="false" /></w:r></w:p></w:sdtContent>
|
||||
</w:sdt>"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_page_with_wrap() {
|
||||
let b = PageNum::new().wrap("none").x_align("left").build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:sdt><w:sdtPr><w:rPr /></w:sdtPr><w:sdtContent><w:p w14:paraId="12345678"><w:pPr><w:rPr /><w:framePr w:wrap="none" w:hAnchor="margin" w:vAnchor="text" w:xAlign="left" w:y="1" /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType="begin" w:dirty="false" /><w:instrText>PAGE</w:instrText><w:fldChar w:fldCharType="separate" w:dirty="false" /><w:t xml:space="preserve">1</w:t><w:fldChar w:fldCharType="end" w:dirty="false" /></w:r></w:p></w:sdtContent>
|
||||
</w:sdt>"#
|
||||
);
|
||||
}
|
||||
}
|
|
@ -40,6 +40,8 @@ pub struct ParagraphProperty {
|
|||
pub paragraph_property_change: Option<ParagraphPropertyChange>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub borders: Option<ParagraphBorders>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub frame_property: Option<FrameProperty>,
|
||||
}
|
||||
|
||||
// 17.3.1.26
|
||||
|
@ -138,6 +140,11 @@ impl ParagraphProperty {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn frame_property(mut self, s: FrameProperty) -> Self {
|
||||
self.frame_property = Some(s);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn hanging_chars(mut self, chars: i32) -> Self {
|
||||
if let Some(indent) = self.indent {
|
||||
self.indent = Some(indent.hanging_chars(chars));
|
||||
|
@ -179,6 +186,7 @@ fn inner_build(p: &ParagraphProperty) -> Vec<u8> {
|
|||
.add_child(&p.run_property)
|
||||
.add_optional_child(&p.style)
|
||||
.add_optional_child(&p.numbering_property)
|
||||
.add_optional_child(&p.frame_property)
|
||||
.add_optional_child(&p.alignment)
|
||||
.add_optional_child(&p.indent)
|
||||
.add_optional_child(&p.line_spacing)
|
||||
|
|
|
@ -32,12 +32,28 @@ impl Footer {
|
|||
self.children.push(FooterChild::Table(Box::new(t)));
|
||||
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 {
|
||||
self.has_numbering = true
|
||||
}
|
||||
self.children
|
||||
.push(FooterChild::StructuredDataTag(Box::new(t)));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum FooterChild {
|
||||
Paragraph(Box<Paragraph>),
|
||||
Table(Box<Table>),
|
||||
PageNum(Box<PageNum>),
|
||||
StructuredDataTag(Box<StructuredDataTag>),
|
||||
}
|
||||
|
||||
|
@ -59,6 +75,12 @@ 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")?;
|
||||
|
@ -78,6 +100,7 @@ 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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,13 @@ impl Header {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> 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 {
|
||||
self.has_numbering = true
|
||||
}
|
||||
|
@ -47,6 +53,7 @@ impl Header {
|
|||
pub enum HeaderChild {
|
||||
Paragraph(Box<Paragraph>),
|
||||
Table(Box<Table>),
|
||||
PageNum(Box<PageNum>),
|
||||
StructuredDataTag(Box<StructuredDataTag>),
|
||||
}
|
||||
|
||||
|
@ -68,6 +75,12 @@ 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")?;
|
||||
|
@ -87,6 +100,7 @@ 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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -925,6 +925,7 @@ impl Docx {
|
|||
Some("header"),
|
||||
);
|
||||
}
|
||||
HeaderChild::PageNum(_) => {}
|
||||
HeaderChild::StructuredDataTag(tag) => {
|
||||
for child in tag.children.iter_mut() {
|
||||
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
||||
|
@ -970,6 +971,7 @@ impl Docx {
|
|||
Some("header"),
|
||||
);
|
||||
}
|
||||
HeaderChild::PageNum(_) => {}
|
||||
HeaderChild::StructuredDataTag(tag) => {
|
||||
for child in tag.children.iter_mut() {
|
||||
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
||||
|
@ -1015,6 +1017,7 @@ impl Docx {
|
|||
Some("header"),
|
||||
);
|
||||
}
|
||||
HeaderChild::PageNum(_) => {}
|
||||
HeaderChild::StructuredDataTag(tag) => {
|
||||
for child in tag.children.iter_mut() {
|
||||
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
||||
|
@ -1059,6 +1062,7 @@ impl Docx {
|
|||
Some("footer"),
|
||||
);
|
||||
}
|
||||
FooterChild::PageNum(_) => {}
|
||||
FooterChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
|
@ -1104,6 +1108,7 @@ impl Docx {
|
|||
Some("footer"),
|
||||
);
|
||||
}
|
||||
FooterChild::PageNum(_) => {}
|
||||
FooterChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
|
@ -1149,6 +1154,7 @@ impl Docx {
|
|||
Some("footer"),
|
||||
);
|
||||
}
|
||||
FooterChild::PageNum(_) => {}
|
||||
FooterChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
|
|
|
@ -30,6 +30,12 @@ impl FromXML for Footer {
|
|||
}
|
||||
continue;
|
||||
}
|
||||
XMLElement::StructuredDataTag => {
|
||||
if let Ok(tag) = StructuredDataTag::read(&mut parser, &attributes) {
|
||||
footer = footer.add_structured_data_tag(tag);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
use std::io::Read;
|
||||
use std::str::FromStr;
|
||||
|
||||
use xml::attribute::OwnedAttribute;
|
||||
use xml::reader::EventReader;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl ElementReader for FrameProperty {
|
||||
fn read<R: Read>(
|
||||
_r: &mut EventReader<R>,
|
||||
attrs: &[OwnedAttribute],
|
||||
) -> Result<Self, ReaderError> {
|
||||
let mut fp = FrameProperty::new();
|
||||
for a in attrs {
|
||||
let local_name = &a.name.local_name;
|
||||
let e = XMLElement::from_str(local_name).unwrap();
|
||||
match e {
|
||||
XMLElement::Wrap => {
|
||||
fp = fp.wrap(a.value.clone());
|
||||
}
|
||||
XMLElement::HeightRule => {
|
||||
fp = fp.h_rule(a.value.clone());
|
||||
}
|
||||
XMLElement::HAnchor => {
|
||||
fp = fp.h_anchor(a.value.clone());
|
||||
}
|
||||
XMLElement::VAnchor => {
|
||||
fp = fp.v_anchor(a.value.clone());
|
||||
}
|
||||
XMLElement::HSpace => {
|
||||
if let Ok(s) = f64::from_str(&a.value) {
|
||||
fp = fp.h_space(s as i32)
|
||||
}
|
||||
}
|
||||
XMLElement::VSpace => {
|
||||
if let Ok(s) = f64::from_str(&a.value) {
|
||||
fp = fp.v_space(s as i32)
|
||||
}
|
||||
}
|
||||
XMLElement::XAlign => fp = fp.x_align(a.value.clone()),
|
||||
XMLElement::YAlign => fp = fp.y_align(a.value.clone()),
|
||||
XMLElement::W => {
|
||||
if let Ok(s) = f64::from_str(&a.value) {
|
||||
fp = fp.width(s as u32)
|
||||
}
|
||||
}
|
||||
XMLElement::H => {
|
||||
if let Ok(s) = f64::from_str(&a.value) {
|
||||
fp = fp.height(s as u32)
|
||||
}
|
||||
}
|
||||
XMLElement::X => {
|
||||
if let Ok(s) = f64::from_str(&a.value) {
|
||||
fp = fp.x(s as i32)
|
||||
}
|
||||
}
|
||||
XMLElement::Y => {
|
||||
if let Ok(s) = f64::from_str(&a.value) {
|
||||
fp = fp.y(s as i32)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(fp)
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ mod errors;
|
|||
mod font_group;
|
||||
mod font_scheme;
|
||||
mod footer;
|
||||
mod frame_property;
|
||||
mod from_xml;
|
||||
mod header;
|
||||
mod header_or_footer_rels;
|
||||
|
|
|
@ -110,6 +110,11 @@ impl ElementReader for ParagraphProperty {
|
|||
p.section_property = Some(sp);
|
||||
}
|
||||
}
|
||||
XMLElement::FrameProperty => {
|
||||
if let Ok(pr) = FrameProperty::read(r, &attributes) {
|
||||
p.frame_property = Some(pr);
|
||||
}
|
||||
}
|
||||
XMLElement::Tabs => {
|
||||
if let Ok(tabs) = Tabs::read(r, &attributes) {
|
||||
for t in tabs.tabs {
|
||||
|
|
|
@ -159,6 +159,18 @@ pub enum XMLElement {
|
|||
StructuredDataTag,
|
||||
Type,
|
||||
PageNumType,
|
||||
FrameProperty,
|
||||
H,
|
||||
HAnchor,
|
||||
HSpace,
|
||||
VAnchor,
|
||||
VSpace,
|
||||
W,
|
||||
Wrap,
|
||||
X,
|
||||
XAlign,
|
||||
Y,
|
||||
YAlign,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
|
@ -392,6 +404,18 @@ impl FromStr for XMLElement {
|
|||
"evenAndOddHeaders" => Ok(XMLElement::EvenAndOddHeaders),
|
||||
"sdt" => Ok(XMLElement::StructuredDataTag),
|
||||
"pgNumType" => Ok(XMLElement::PageNumType),
|
||||
"framePr" => Ok(XMLElement::FrameProperty),
|
||||
"h" => Ok(XMLElement::H),
|
||||
"hAnchor" => Ok(XMLElement::HAnchor),
|
||||
"hSpace" => Ok(XMLElement::HSpace),
|
||||
"vAnchor" => Ok(XMLElement::VAnchor),
|
||||
"vSpace" => Ok(XMLElement::VSpace),
|
||||
"w" => Ok(XMLElement::W),
|
||||
"wrap" => Ok(XMLElement::Wrap),
|
||||
"x" => Ok(XMLElement::X),
|
||||
"xAlign" => Ok(XMLElement::XAlign),
|
||||
"y" => Ok(XMLElement::Y),
|
||||
"yAlign" => Ok(XMLElement::YAlign),
|
||||
"type" => Ok(XMLElement::Type),
|
||||
_ => Ok(XMLElement::Unsupported),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::XMLBuilder;
|
||||
use super::XmlEvent;
|
||||
use crate::types::*;
|
||||
use crate::FrameProperty;
|
||||
|
||||
const EXPECT_MESSAGE: &str = "should write buf";
|
||||
|
||||
|
@ -567,6 +568,65 @@ impl XMLBuilder {
|
|||
self.close()
|
||||
}
|
||||
|
||||
/**
|
||||
pub h_space: Option<String>,
|
||||
pub v_space: Option<String>,
|
||||
*/
|
||||
|
||||
pub(crate) fn frame_property(mut self, prop: &FrameProperty) -> Self {
|
||||
let mut w = XmlEvent::start_element("w:framePr");
|
||||
let wrap: String = prop.wrap.iter().cloned().collect();
|
||||
if prop.wrap.is_some() {
|
||||
w = w.attr("w:wrap", &wrap);
|
||||
}
|
||||
let h_rule: String = prop.h_rule.iter().cloned().collect();
|
||||
if prop.h_rule.is_some() {
|
||||
w = w.attr("w:hRule", &h_rule);
|
||||
}
|
||||
let h_anchor: String = prop.h_anchor.iter().cloned().collect();
|
||||
if prop.h_anchor.is_some() {
|
||||
w = w.attr("w:hAnchor", &h_anchor);
|
||||
}
|
||||
let v_anchor: String = prop.v_anchor.iter().cloned().collect();
|
||||
if prop.v_anchor.is_some() {
|
||||
w = w.attr("w:vAnchor", &v_anchor);
|
||||
}
|
||||
let x_align: String = prop.x_align.iter().cloned().collect();
|
||||
if prop.x_align.is_some() {
|
||||
w = w.attr("w:xAlign", &x_align);
|
||||
}
|
||||
let y_align: String = prop.y_align.iter().cloned().collect();
|
||||
if prop.y_align.is_some() {
|
||||
w = w.attr("w:yAlign", &y_align);
|
||||
}
|
||||
let x: String = format!("{}", prop.x.unwrap_or_default());
|
||||
if prop.x.is_some() {
|
||||
w = w.attr("w:x", &x);
|
||||
}
|
||||
let y: String = format!("{}", prop.y.unwrap_or_default());
|
||||
if prop.y.is_some() {
|
||||
w = w.attr("w:y", &y);
|
||||
}
|
||||
let h_space: String = format!("{}", prop.h_space.unwrap_or_default());
|
||||
if prop.h_space.is_some() {
|
||||
w = w.attr("w:h_space", &h_space);
|
||||
}
|
||||
let v_space: String = format!("{}", prop.v_space.unwrap_or_default());
|
||||
if prop.v_space.is_some() {
|
||||
w = w.attr("w:v_space", &v_space);
|
||||
}
|
||||
let width: String = format!("{}", prop.w.unwrap_or_default());
|
||||
if prop.w.is_some() {
|
||||
w = w.attr("w:w", &width);
|
||||
}
|
||||
let h: String = format!("{}", prop.h.unwrap_or_default());
|
||||
if prop.h.is_some() {
|
||||
w = w.attr("w:h", &h);
|
||||
}
|
||||
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());
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { PageNum } from "./page-num";
|
||||
import { Paragraph } from "./paragraph";
|
||||
import { Table } from "./table";
|
||||
|
||||
export class Footer {
|
||||
hasNumberings = false;
|
||||
children: (Paragraph | Table)[] = [];
|
||||
children: (Paragraph | Table | PageNum)[] = [];
|
||||
|
||||
addParagraph(p: Paragraph) {
|
||||
if (p.hasNumberings) {
|
||||
|
@ -20,4 +21,9 @@ export class Footer {
|
|||
this.children.push(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
addPageNum(p: PageNum) {
|
||||
this.children.push(p);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { PageNum } from "./page-num";
|
||||
import { Paragraph } from "./paragraph";
|
||||
import { Table } from "./table";
|
||||
|
||||
export class Header {
|
||||
hasNumberings = false;
|
||||
children: (Paragraph | Table)[] = [];
|
||||
children: (Paragraph | Table | PageNum)[] = [];
|
||||
|
||||
addParagraph(p: Paragraph) {
|
||||
if (p.hasNumberings) {
|
||||
|
@ -20,4 +21,9 @@ export class Header {
|
|||
this.children.push(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
addPageNum(p: PageNum) {
|
||||
this.children.push(p);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,8 +422,11 @@ export class Docx {
|
|||
this.sectionProperty._header.children.forEach((c) => {
|
||||
if (c instanceof Paragraph) {
|
||||
header = header.add_paragraph(build(c));
|
||||
} else {
|
||||
} 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);
|
||||
|
@ -434,8 +437,11 @@ export class Docx {
|
|||
this.sectionProperty._firstHeader.children.forEach((c) => {
|
||||
if (c instanceof Paragraph) {
|
||||
header = header.add_paragraph(build(c));
|
||||
} else {
|
||||
} 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);
|
||||
|
@ -446,8 +452,11 @@ export class Docx {
|
|||
this.sectionProperty._evenHeader.children.forEach((c) => {
|
||||
if (c instanceof Paragraph) {
|
||||
header = header.add_paragraph(build(c));
|
||||
} else {
|
||||
} 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);
|
||||
|
@ -458,8 +467,11 @@ export class Docx {
|
|||
this.sectionProperty._footer.children.forEach((c) => {
|
||||
if (c instanceof Paragraph) {
|
||||
footer = footer.add_paragraph(build(c));
|
||||
} else {
|
||||
} 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);
|
||||
|
@ -470,8 +482,11 @@ export class Docx {
|
|||
this.sectionProperty._firstFooter.children.forEach((c) => {
|
||||
if (c instanceof Paragraph) {
|
||||
footer = footer.add_paragraph(build(c));
|
||||
} else {
|
||||
} 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);
|
||||
|
@ -482,8 +497,11 @@ export class Docx {
|
|||
this.sectionProperty._evenFooter.children.forEach((c) => {
|
||||
if (c instanceof Paragraph) {
|
||||
footer = footer.add_paragraph(build(c));
|
||||
} else {
|
||||
} 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);
|
||||
|
@ -668,5 +686,6 @@ export * from "./tab";
|
|||
export * from "./json";
|
||||
export * from "./webextension";
|
||||
export * from "./header";
|
||||
export * from "./page-num";
|
||||
export * from "./footer";
|
||||
export * from "./image";
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export interface 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, }
|
|
@ -6,6 +6,9 @@ import {
|
|||
SectionPropertyJSON,
|
||||
} from "..";
|
||||
import { LineSpacingJSON } from "./line_spacing";
|
||||
import { FrameProperty as FramePropertyJSON } from "./bindings/FrameProperty";
|
||||
|
||||
export { FrameProperty as FramePropertyJSON } from "./bindings/FrameProperty";
|
||||
|
||||
export type ParagraphChildJSON =
|
||||
| RunJSON
|
||||
|
@ -76,6 +79,7 @@ export type ParagraphPropertyJSON = {
|
|||
};
|
||||
sectionProperty?: SectionPropertyJSON;
|
||||
tabs: CustomTabStopJSON[];
|
||||
frameProperty?: FramePropertyJSON;
|
||||
};
|
||||
|
||||
export type ParagraphJSON = {
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
return pageNum;
|
||||
}
|
||||
}
|
|
@ -75,7 +75,7 @@ export class SectionProperty {
|
|||
return this;
|
||||
}
|
||||
|
||||
pageTypeNum({ start, chapStyle }: { start: number; chapStyle: string }) {
|
||||
pageTypeNum({ start, chapStyle }: { start?: number; chapStyle?: string }) {
|
||||
this._pageTypeNum = { start, chapStyle };
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docx-wasm",
|
||||
"version": "0.4.12-beta1",
|
||||
"version": "0.4.12-beta5",
|
||||
"main": "dist/node/index.js",
|
||||
"browser": "dist/web/index.js",
|
||||
"author": "bokuweb <bokuweb12@gmail.com>",
|
||||
|
|
|
@ -27,4 +27,9 @@ 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use wasm_bindgen::prelude::*;
|
|||
pub struct Header(docx_rs::Header);
|
||||
|
||||
#[wasm_bindgen(js_name = createHeader)]
|
||||
pub fn create_footer() -> Header {
|
||||
pub fn create_header() -> Header {
|
||||
Header(docx_rs::Header::new())
|
||||
}
|
||||
|
||||
|
@ -27,4 +27,9 @@ 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ mod level_override;
|
|||
mod line_spacing;
|
||||
mod numbering;
|
||||
mod page_margin;
|
||||
mod page_num;
|
||||
mod page_num_type;
|
||||
mod paragraph;
|
||||
mod pic;
|
||||
|
@ -41,6 +42,7 @@ pub use level_override::*;
|
|||
pub use line_spacing::*;
|
||||
pub use numbering::*;
|
||||
pub use page_margin::*;
|
||||
pub use page_num::*;
|
||||
pub use page_num_type::*;
|
||||
pub use paragraph::*;
|
||||
pub use pic::*;
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug)]
|
||||
pub struct PageNum(docx_rs::PageNum);
|
||||
|
||||
#[wasm_bindgen(js_name = createPageNum)]
|
||||
pub fn create_page_num() -> PageNum {
|
||||
PageNum(docx_rs::PageNum::new())
|
||||
}
|
||||
|
||||
impl PageNum {
|
||||
pub fn take(self) -> docx_rs::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
|
||||
}
|
||||
}
|
|
@ -36217,6 +36217,13 @@ Object {
|
|||
"hasNumbering": false,
|
||||
"id": "2948A9FC",
|
||||
"property": Object {
|
||||
"frameProperty": Object {
|
||||
"hAnchor": "margin",
|
||||
"vAnchor": "text",
|
||||
"wrap": "none",
|
||||
"xAlign": "right",
|
||||
"y": 1,
|
||||
},
|
||||
"runProperty": Object {
|
||||
"style": "ae",
|
||||
},
|
||||
|
@ -36358,6 +36365,13 @@ Object {
|
|||
"hasNumbering": false,
|
||||
"id": "66B15C28",
|
||||
"property": Object {
|
||||
"frameProperty": Object {
|
||||
"hAnchor": "margin",
|
||||
"vAnchor": "text",
|
||||
"wrap": "none",
|
||||
"xAlign": "right",
|
||||
"y": 1,
|
||||
},
|
||||
"runProperty": Object {
|
||||
"style": "ae",
|
||||
},
|
||||
|
@ -105236,6 +105250,16 @@ Object {
|
|||
"name": "envelope address",
|
||||
"next": null,
|
||||
"paragraphProperty": Object {
|
||||
"frameProperty": Object {
|
||||
"h": 2268,
|
||||
"hAnchor": "page",
|
||||
"hRule": "exact",
|
||||
"hSpace": 142,
|
||||
"w": 6804,
|
||||
"wrap": "auto",
|
||||
"xAlign": "center",
|
||||
"yAlign": "bottom",
|
||||
},
|
||||
"indent": Object {
|
||||
"end": null,
|
||||
"firstLineChars": null,
|
||||
|
@ -119878,6 +119902,16 @@ Object {
|
|||
"name": "envelope address",
|
||||
"next": null,
|
||||
"paragraphProperty": Object {
|
||||
"frameProperty": Object {
|
||||
"h": 1980,
|
||||
"hAnchor": "page",
|
||||
"hRule": "exact",
|
||||
"hSpace": 180,
|
||||
"w": 7920,
|
||||
"wrap": "auto",
|
||||
"xAlign": "center",
|
||||
"yAlign": "bottom",
|
||||
},
|
||||
"indent": Object {
|
||||
"end": null,
|
||||
"firstLineChars": null,
|
||||
|
@ -137972,6 +138006,13 @@ Object {
|
|||
"next": null,
|
||||
"paragraphProperty": Object {
|
||||
"alignment": "right",
|
||||
"frameProperty": Object {
|
||||
"hAnchor": "text",
|
||||
"hSpace": 181,
|
||||
"vAnchor": "text",
|
||||
"wrap": "around",
|
||||
"y": 1,
|
||||
},
|
||||
"runProperty": Object {},
|
||||
"tabs": Array [],
|
||||
},
|
||||
|
@ -139121,6 +139162,9 @@ Object {
|
|||
"name": "TRILOGO",
|
||||
"next": null,
|
||||
"paragraphProperty": Object {
|
||||
"frameProperty": Object {
|
||||
"wrap": "around",
|
||||
},
|
||||
"lineSpacing": Object {
|
||||
"before": 5280,
|
||||
},
|
||||
|
@ -156530,6 +156574,13 @@ Object {
|
|||
"hasNumbering": false,
|
||||
"id": "638F96CF",
|
||||
"property": Object {
|
||||
"frameProperty": Object {
|
||||
"hAnchor": "margin",
|
||||
"vAnchor": "text",
|
||||
"wrap": "around",
|
||||
"xAlign": "center",
|
||||
"y": 1,
|
||||
},
|
||||
"runProperty": Object {},
|
||||
"tabs": Array [],
|
||||
},
|
||||
|
@ -171523,6 +171574,24 @@ exports[`writer should write page size 3`] = `
|
|||
</w:num></w:numbering>"
|
||||
`;
|
||||
|
||||
exports[`writer should write pageNum in header 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
<Relationship Id=\\"rId1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\\" Target=\\"styles.xml\\" />
|
||||
<Relationship Id=\\"rId2\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\\" Target=\\"fontTable.xml\\" />
|
||||
<Relationship Id=\\"rId3\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\\" Target=\\"settings.xml\\" />
|
||||
<Relationship Id=\\"rId5\\" Type=\\"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\\" Target=\\"commentsExtended.xml\\" />
|
||||
<Relationship Id=\\"rIdHeader1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\\" Target=\\"header1.xml\\" />
|
||||
</Relationships>"
|
||||
`;
|
||||
|
||||
exports[`writer should write pageNum in header 2`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?>
|
||||
<w:document xmlns:o=\\"urn:schemas-microsoft-com:office:office\\" xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:v=\\"urn:schemas-microsoft-com:vml\\" xmlns:w=\\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\\" xmlns:w10=\\"urn:schemas-microsoft-com:office:word\\" xmlns:wp=\\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\\" xmlns:wps=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\\" xmlns:wpg=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\\" xmlns:mc=\\"http://schemas.openxmlformats.org/markup-compatibility/2006\\" xmlns:wp14=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\\" xmlns:w14=\\"http://schemas.microsoft.com/office/word/2010/wordml\\" xmlns:w15=\\"http://schemas.microsoft.com/office/word/2012/wordml\\" mc:Ignorable=\\"w14 wp14\\">
|
||||
<w:body><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello world!!</w:t></w:r></w:p><w:sectPr><w:pgSz w:w=\\"11906\\" w:h=\\"16838\\" /><w:pgMar w:top=\\"1985\\" w:right=\\"1701\\" w:bottom=\\"1701\\" w:left=\\"1701\\" w:header=\\"851\\" w:footer=\\"992\\" w:gutter=\\"0\\" /><w:cols w:space=\\"425\\" w:num=\\"1\\" /><w:headerReference w:type=\\"default\\" r:id=\\"rIdHeader1\\" /></w:sectPr></w:body>
|
||||
</w:document>"
|
||||
`;
|
||||
|
||||
exports[`writer should write paragraph delete 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
|
|
|
@ -1043,4 +1043,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();
|
||||
const header = new w.Header().addParagraph(p).addPageNum(page);
|
||||
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/)) {
|
||||
expect(z.readAsText(e)).toMatchSnapshot();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue