Skip to content

Commit

Permalink
Support default section header (#115)
Browse files Browse the repository at this point in the history
* feat: Add minimum header

* feat: Support minimum header feature

* fix: fix snaps
  • Loading branch information
bokuweb committed Aug 13, 2020
1 parent b08c560 commit c0aab13
Show file tree
Hide file tree
Showing 57 changed files with 617 additions and 107 deletions.
110 changes: 36 additions & 74 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions docx-core/examples/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use docx_rs::*;

pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./output/header.docx");
let file = std::fs::File::create(&path).unwrap();
Docx::new()
.add_header_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")))
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("World")))
.build()
.pack(file)?;
Ok(())
}
4 changes: 4 additions & 0 deletions docx-core/src/documents/content_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ impl ContentTypes {
"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"
.to_owned(),
);
self.types.insert(
"/word/header1.xml".to_owned(),
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml".to_owned(),
);
self
}
}
Expand Down
2 changes: 1 addition & 1 deletion docx-core/src/documents/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ mod tests {
str::from_utf8(&b).unwrap(),
r#"<?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" mc:Ignorable="w14 wp14">
<w:body><w:p><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</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:body><w:p><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</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:headerReference w:type="default" r:id="rId4" /><w:cols w:space="425" />
<w:docGrid w:type="lines" w:linePitch="360" />
</w:sectPr></w:body>
</w:document>"#
Expand Down
9 changes: 7 additions & 2 deletions docx-core/src/documents/document_rels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,24 @@ impl BuildXML for DocumentRels {
"rId3",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings",
"settings.xml",
)
.relationship(
"rId4",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
"header1.xml",
);

if self.has_comments {
b = b.relationship(
"rId4",
"rId5",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
"comments.xml",
)
}

if self.has_numberings {
b = b.relationship(
"rId5",
"rId6",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
"numbering.xml",
)
Expand Down
37 changes: 37 additions & 0 deletions docx-core/src/documents/elements/header_reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;

use serde::Serialize;

#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HeaderReference {
header_type: String,
id: String,
}

impl Default for HeaderReference {
fn default() -> HeaderReference {
HeaderReference {
header_type: "default".to_owned(),
id: "rId4".to_owned(),
}
}
}

impl HeaderReference {
pub fn new(t: impl Into<String>, id: impl Into<String>) -> HeaderReference {
HeaderReference {
header_type: t.into(),
id: id.into(),
}
}
}

impl BuildXML for HeaderReference {
fn build(&self) -> Vec<u8> {
XMLBuilder::new()
.header_reference(&self.header_type, &self.id)
.build()
}
}
2 changes: 2 additions & 0 deletions docx-core/src/documents/elements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod doc_defaults;
mod drawing;
mod font;
mod grid_span;
mod header_reference;
mod highlight;
mod indent;
mod indent_level;
Expand Down Expand Up @@ -97,6 +98,7 @@ pub use doc_defaults::*;
pub use drawing::*;
pub use font::*;
pub use grid_span::*;
pub use header_reference::*;
pub use highlight::*;
pub use indent::*;
pub use indent_level::*;
Expand Down
5 changes: 4 additions & 1 deletion docx-core/src/documents/elements/section_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub struct SectionProperty {
page_margin: PageMargin,
columns: usize,
document_grid: usize,
header_reference: HeaderReference,
}

impl SectionProperty {
Expand All @@ -26,6 +27,7 @@ impl Default for SectionProperty {
page_margin: PageMargin::new(),
columns: 425,
document_grid: 360,
header_reference: HeaderReference::default(),
}
}
}
Expand All @@ -36,6 +38,7 @@ impl BuildXML for SectionProperty {
b.open_section_property()
.add_child(&self.page_size)
.add_child(&self.page_margin)
.add_child(&self.header_reference)
.columns(&format!("{}", &self.columns))
.document_grid("lines", &format!("{}", &self.document_grid))
.close()
Expand All @@ -57,7 +60,7 @@ mod tests {
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<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" />
r#"<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:headerReference w:type="default" r:id="rId4" /><w:cols w:space="425" />
<w:docGrid w:type="lines" w:linePitch="360" />
</w:sectPr>"#
);
Expand Down
105 changes: 105 additions & 0 deletions docx-core/src/documents/header.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize;

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

#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Header {
pub children: Vec<HeaderChild>,
}

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

pub fn add_paragraph(mut self, p: Paragraph) -> Self {
// TODO: support numberings
// if p.has_numbering {
// self.has_numbering = true
// }
self.children.push(HeaderChild::Paragraph(p));
self
}

pub fn add_table(mut self, t: Table) -> Self {
// TODO: support numberings
// if t.has_numbering {
// self.has_numbering = true
// }
self.children.push(HeaderChild::Table(t));
self
}
}

impl Default for Header {
fn default() -> Self {
Self { children: vec![] }
}
}

#[derive(Debug, Clone, PartialEq)]
pub enum HeaderChild {
Paragraph(Paragraph),
Table(Table),
}

impl Serialize for HeaderChild {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
HeaderChild::Paragraph(ref p) => {
let mut t = serializer.serialize_struct("Paragraph", 2)?;
t.serialize_field("type", "paragraph")?;
t.serialize_field("data", p)?;
t.end()
}
HeaderChild::Table(ref c) => {
let mut t = serializer.serialize_struct("Table", 2)?;
t.serialize_field("type", "table")?;
t.serialize_field("data", c)?;
t.end()
}
}
}
}

impl BuildXML for Header {
fn build(&self) -> Vec<u8> {
let mut b = XMLBuilder::new();
b = b.declaration(Some(true)).open_header();

for c in &self.children {
match c {
HeaderChild::Paragraph(p) => b = b.add_child(p),
HeaderChild::Table(t) => b = b.add_child(t),
}
}
b.close().build()
}
}

#[cfg(test)]
mod tests {

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

#[test]
fn test_settings() {
let c = Header::new();
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:hdr xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:o="urn:schemas-microsoft-com:office:office" 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" mc:Ignorable="w14 wp14" />"#
);
}
}
23 changes: 23 additions & 0 deletions docx-core/src/documents/header_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
use std::sync::atomic::AtomicUsize;
#[cfg(not(test))]
static HEADER_ID: AtomicUsize = AtomicUsize::new(1);
#[cfg(not(test))]
pub fn generate_header_id() -> usize {
use std::sync::atomic::Ordering;
let id = HEADER_ID.load(Ordering::Relaxed);
HEADER_ID.store(id.wrapping_add(1), Ordering::Relaxed);
id
}
#[cfg(test)]
pub fn generate_header_id() -> usize {
123
}
pub fn create_header_rid(id: usize) -> String {
format!("rIdImage{}", id)
}
*/
17 changes: 17 additions & 0 deletions docx-core/src/documents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ mod document;
mod document_rels;
mod elements;
mod font_table;
mod header;
mod header_id;
mod history_id;
mod numberings;
mod pic_id;
Expand All @@ -25,6 +27,7 @@ pub use document::*;
pub use document_rels::*;
pub use elements::*;
pub use font_table::*;
pub use header::*;
pub use numberings::*;
pub use rels::*;
pub use settings::*;
Expand All @@ -47,6 +50,7 @@ pub struct Docx {
pub settings: Settings,
pub font_table: FontTable,
pub media: Vec<(usize, Vec<u8>)>,
pub header: Header,
}

impl Default for Docx {
Expand All @@ -62,6 +66,7 @@ impl Default for Docx {
let comments = Comments::new();
let numberings = Numberings::new();
let media = vec![];
let header = Header::new();
Docx {
content_type,
rels,
Expand All @@ -74,6 +79,7 @@ impl Default for Docx {
font_table,
numberings,
media,
header,
}
}
}
Expand Down Expand Up @@ -132,6 +138,16 @@ impl Docx {
self
}

pub fn add_header_paragraph(mut self, p: Paragraph) -> Docx {
if p.has_numbering {
// If this document has numbering, set numberings.xml to document_rels.
// This is because numberings.xml without numbering cause an error on word online.
self.document_rels.has_numberings = true;
}
self.header = self.header.add_paragraph(p);
self
}

pub fn add_abstract_numbering(mut self, num: AbstractNumbering) -> Docx {
self.numberings = self.numberings.add_abstract_numbering(num);
self
Expand Down Expand Up @@ -170,6 +186,7 @@ impl Docx {
font_table: self.font_table.build(),
numberings: self.numberings.build(),
media: images,
header: self.header.build(),
}
}

Expand Down
1 change: 1 addition & 0 deletions docx-core/src/documents/xml_docx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct XMLDocx {
pub font_table: Vec<u8>,
pub numberings: Vec<u8>,
pub media: Vec<(usize, Vec<u8>)>,
pub header: Vec<u8>,
}

impl XMLDocx {
Expand Down
2 changes: 2 additions & 0 deletions docx-core/src/xml_builder/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ impl XMLBuilder {
closed_with_str!(charset, "w:charset");

open!(open_section_property, "w:sectPr");
closed!(header_reference, "w:headerReference", "w:type", "r:id");

closed_with_str!(type_tag, "w:type");
closed!(page_size, "w:pgSz", "w:w", "w:h");
closed!(
Expand Down
Loading

0 comments on commit c0aab13

Please sign in to comment.