Support default footer (#366)

* feat: Support default footer writer with rust

* feat: Support footer for default section with js

* fix: improve footer interface
main
bokuweb 2021-11-25 01:49:27 +09:00 committed by GitHub
parent f44faea75f
commit 025aee280f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 1377 additions and 890 deletions

View File

@ -0,0 +1,14 @@
use docx_rs::*;
pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./output/footer.docx");
let file = std::fs::File::create(&path).unwrap();
let footer =
Footer::new().add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")));
Docx::new()
.footer(footer)
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("World")))
.build()
.pack(file)?;
Ok(())
}

View File

@ -12,6 +12,7 @@ pub struct ContentTypes {
types: BTreeMap<String, String>,
web_extension_count: usize,
custom_xml_count: usize,
footer_count: usize,
}
impl ContentTypes {
@ -114,6 +115,15 @@ impl ContentTypes {
self.custom_xml_count += 1;
self
}
pub fn add_footer(mut self) -> Self {
self.types.insert(
format!("/word/footer{}.xml", self.footer_count),
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml".to_owned(),
);
self.footer_count += 1;
self
}
}
impl Default for ContentTypes {
@ -122,6 +132,7 @@ impl Default for ContentTypes {
types: BTreeMap::new(),
web_extension_count: 1,
custom_xml_count: 1,
footer_count: 1,
}
}
}
@ -200,7 +211,8 @@ mod tests {
ContentTypes {
types,
web_extension_count: 1,
custom_xml_count: 1
custom_xml_count: 1,
footer_count: 1,
},
c
);

View File

@ -149,6 +149,11 @@ impl Document {
self.section_property = property;
self
}
pub fn footer_reference(mut self, r: FooterReference) -> Self {
self.section_property = self.section_property.footer_reference(r);
self
}
}
impl BuildXML for DocumentChild {

View File

@ -11,6 +11,7 @@ pub struct DocumentRels {
pub has_numberings: bool,
pub image_ids: Vec<usize>,
pub custom_xml_count: usize,
pub footer_count: usize,
}
impl DocumentRels {
@ -31,6 +32,7 @@ impl Default for DocumentRels {
has_numberings: false,
image_ids: vec![],
custom_xml_count: 0,
footer_count: 0,
}
}
}
@ -83,6 +85,14 @@ impl BuildXML for DocumentRels {
)
}
for i in 0..self.footer_count {
b = b.relationship(
&create_footer_rid(i + 1),
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
&format!("footer{}.xml", i + 1),
)
}
for i in 0..self.custom_xml_count {
b = b.relationship(
&format!("rId{}", i + 8),

View File

@ -0,0 +1,28 @@
use crate::documents::BuildXML;
use crate::xml_builder::*;
use serde::Serialize;
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FooterReference {
footer_type: String,
id: String,
}
impl FooterReference {
pub fn new(t: impl Into<String>, id: impl Into<String>) -> FooterReference {
FooterReference {
footer_type: t.into(),
id: id.into(),
}
}
}
impl BuildXML for FooterReference {
fn build(&self) -> Vec<u8> {
XMLBuilder::new()
.footer_reference(&self.footer_type, &self.id)
.build()
}
}

View File

@ -25,6 +25,7 @@ mod drawing;
mod font;
mod grid_span;
mod header_reference;
mod footer_reference;
mod highlight;
mod indent;
mod indent_level;
@ -121,6 +122,7 @@ pub use drawing::*;
pub use font::*;
pub use grid_span::*;
pub use header_reference::*;
pub use footer_reference::*;
pub use highlight::*;
pub use indent::*;
pub use indent_level::*;

View File

@ -13,6 +13,7 @@ pub struct SectionProperty {
columns: usize,
doc_grid: DocGrid,
header_reference: HeaderReference,
footer_reference: Option<FooterReference>,
section_type: Option<SectionType>,
}
@ -40,6 +41,11 @@ impl SectionProperty {
self.doc_grid = doc_grid;
self
}
pub fn footer_reference(mut self, r: FooterReference) -> Self {
self.footer_reference = Some(r);
self
}
}
impl Default for SectionProperty {
@ -50,6 +56,7 @@ impl Default for SectionProperty {
columns: 425,
doc_grid: DocGrid::default(),
header_reference: HeaderReference::default(),
footer_reference: None,
section_type: None,
}
}
@ -64,7 +71,8 @@ impl BuildXML for SectionProperty {
.add_child(&self.page_margin)
.add_child(&self.header_reference)
.columns(&format!("{}", &self.columns))
.add_child(&self.doc_grid);
.add_child(&self.doc_grid)
.add_optional_child(&self.footer_reference);
if let Some(t) = self.section_type {
b = b.type_tag(&t.to_string());
@ -90,4 +98,14 @@ mod tests {
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>"#
);
}
#[test]
fn test_section_property_with_footer() {
let c = SectionProperty::new().footer_reference(FooterReference::new("default", "rId6"));
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:headerReference w:type="default" r:id="rId4" /><w:cols w:space="425" /><w:docGrid w:type="lines" w:linePitch="360" /><w:footerReference w:type="default" r:id="rId6" /></w:sectPr>"#
);
}
}

View File

@ -0,0 +1,107 @@
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 Footer {
pub has_numbering: bool,
pub children: Vec<FooterChild>,
}
impl Footer {
pub fn new() -> Footer {
Default::default()
}
pub fn add_paragraph(mut self, p: Paragraph) -> Self {
if p.has_numbering {
self.has_numbering = true
}
self.children.push(FooterChild::Paragraph(p));
self
}
pub fn add_table(mut self, t: Table) -> Self {
if t.has_numbering {
self.has_numbering = true
}
self.children.push(FooterChild::Table(t));
self
}
}
impl Default for Footer {
fn default() -> Self {
Self {
children: vec![],
has_numbering: false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FooterChild {
Paragraph(Paragraph),
Table(Table),
}
impl Serialize for FooterChild {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
FooterChild::Paragraph(ref p) => {
let mut t = serializer.serialize_struct("Paragraph", 2)?;
t.serialize_field("type", "paragraph")?;
t.serialize_field("data", p)?;
t.end()
}
FooterChild::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 Footer {
fn build(&self) -> Vec<u8> {
let mut b = XMLBuilder::new();
b = b.declaration(Some(true)).open_footer();
for c in &self.children {
match c {
FooterChild::Paragraph(p) => b = b.add_child(p),
FooterChild::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 = Footer::new();
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:ftr 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" />"#
);
}
}

View File

@ -0,0 +1,24 @@
/*
#[cfg(not(test))]
use std::sync::atomic::AtomicUsize;
#[cfg(not(test))]
static FOOTER_ID: AtomicUsize = AtomicUsize::new(1);
#[cfg(not(test))]
pub fn generate_pic_id() -> usize {
use std::sync::atomic::Ordering;
let id = FOOTER_ID.load(Ordering::Relaxed);
FOOTER_ID.store(id.wrapping_add(1), Ordering::Relaxed);
id
}
#[cfg(test)]
pub fn generate_footer_id() -> usize {
123
}
*/
pub fn create_footer_rid(id: usize) -> String {
format!("rIdFooter{}", id)
}

View File

@ -12,6 +12,8 @@ mod document;
mod document_rels;
mod elements;
mod font_table;
mod footer;
mod footer_id;
mod header;
mod header_id;
mod history_id;
@ -43,6 +45,8 @@ pub use document::*;
pub use document_rels::*;
pub use elements::*;
pub use font_table::*;
pub use footer::*;
pub use footer_id::*;
pub use header::*;
pub use numberings::*;
pub use rels::*;
@ -71,6 +75,7 @@ pub struct Docx {
pub font_table: FontTable,
pub media: Vec<(usize, Vec<u8>)>,
pub header: Header,
pub footer: Option<Footer>,
pub comments_extended: CommentsExtended,
pub web_settings: WebSettings,
pub taskpanes: Option<Taskpanes>,
@ -111,6 +116,7 @@ impl Default for Docx {
font_table,
media,
header,
footer: None,
comments_extended,
web_settings,
taskpanes: None,
@ -219,6 +225,49 @@ impl Docx {
self
}
pub fn footer(mut self, footer: Footer) -> Docx {
if footer.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;
}
if self.footer.is_none() {
self.document.section_property = self
.document
.section_property
// Add default footer reference
.footer_reference(FooterReference::new("default", create_footer_rid(1)));
self.document_rels.footer_count += 1;
self.content_type = self.content_type.add_footer();
}
self.footer = Some(footer);
self
}
pub fn add_footer_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;
}
if self.footer.is_none() {
self.footer = Some(Footer::new());
self.document.section_property = self
.document
.section_property
// Add default footer reference
.footer_reference(FooterReference::new("default", create_footer_rid(1)));
self.document_rels.footer_count += 1;
self.content_type = self.content_type.add_footer();
}
if let Some(footer) = self.footer {
let footer = footer.add_paragraph(p);
self.footer = Some(footer);
}
self
}
pub fn add_abstract_numbering(mut self, num: AbstractNumbering) -> Docx {
self.numberings = self.numberings.add_abstract_numbering(num);
self
@ -320,7 +369,6 @@ impl Docx {
self.update_comments();
let (image_ids, images) = self.create_images();
let web_extensions = self.web_extensions.iter().map(|ext| ext.build()).collect();
let custom_items = self.custom_items.iter().map(|xml| xml.build()).collect();
let custom_item_props = self.custom_item_props.iter().map(|p| p.build()).collect();
@ -332,6 +380,8 @@ impl Docx {
self.document_rels.image_ids = image_ids;
let footer = self.footer.as_ref().map(|footer| footer.build());
XMLDocx {
content_type: self.content_type.build(),
rels: self.rels.build(),
@ -345,6 +395,7 @@ impl Docx {
numberings: self.numberings.build(),
media: images,
header: self.header.build(),
footer,
comments_extended: self.comments_extended.build(),
taskpanes: self.taskpanes.map(|taskpanes| taskpanes.build()),
taskpanes_rels: self.taskpanes_rels.build(),

View File

@ -18,6 +18,7 @@ pub struct XMLDocx {
pub numberings: Vec<u8>,
pub media: Vec<(usize, Vec<u8>)>,
pub header: Vec<u8>,
pub footer: Option<Vec<u8>>,
pub comments_extended: Vec<u8>,
pub taskpanes: Option<Vec<u8>>,
pub taskpanes_rels: Vec<u8>,

View File

@ -11,7 +11,6 @@ impl XMLBuilder {
"distR"
);
#[allow(clippy::too_many_arguments)]
open!(
open_wp_anchor,
"wp:anchor",

View File

@ -262,6 +262,7 @@ impl XMLBuilder {
open!(open_section_property, "w:sectPr");
closed!(header_reference, "w:headerReference", "w:type", "r:id");
closed!(footer_reference, "w:footerReference", "w:type", "r:id");
closed_with_str!(type_tag, "w:type");
closed!(page_size, "w:pgSz", "w:w", "w:h");

View File

@ -0,0 +1,49 @@
use super::XMLBuilder;
use super::XmlEvent;
impl XMLBuilder {
pub(crate) fn open_footer(mut self) -> Self {
self.writer
.write(
XmlEvent::start_element("w:ftr")
.attr(
"xmlns:r",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
)
.attr("xmlns:o", "urn:schemas-microsoft-com:office:office")
.attr("xmlns:v", "urn:schemas-microsoft-com:vml")
.attr(
"xmlns:w",
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
)
.attr("xmlns:w10", "urn:schemas-microsoft-com:office:word")
.attr(
"xmlns:wp",
"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
)
.attr(
"xmlns:wps",
"http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
)
.attr(
"xmlns:wpg",
"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
)
.attr(
"xmlns:mc",
"http://schemas.openxmlformats.org/markup-compatibility/2006",
)
.attr(
"xmlns:wp14",
"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
)
.attr(
"xmlns:w14",
"http://schemas.microsoft.com/office/word/2010/wordml",
)
.attr("mc:Ignorable", "w14 wp14"),
)
.expect("should write to buf");
self
}
}

View File

@ -10,6 +10,7 @@ mod document;
mod drawing;
mod elements;
mod fonts;
mod footer;
mod header;
mod numbering;
mod pic;

View File

@ -48,6 +48,11 @@ where
zip.start_file("word/commentsExtended.xml", options)?;
zip.write_all(&xml.comments_extended)?;
if let Some(footer) = xml.footer {
zip.start_file("word/footer1.xml", options)?;
zip.write_all(&footer)?;
}
if !xml.media.is_empty() {
zip.add_directory("word/media/", Default::default())?;
for m in xml.media {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
import { Paragraph } from "./paragraph";
export class Footer {
hasNumberings = false;
children: Paragraph[] = [];
addParagraph(p: Paragraph) {
if (p.hasNumberings) {
this.hasNumberings = true;
}
this.children.push(p);
return this;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import { DocGridType } from ".";
import { Footer } from "./footer";
export type DocGrid = {
gridType: DocGridType;
@ -16,6 +17,7 @@ export class SectionProperty {
gridType: "lines",
linePitch: 360,
};
_footer: Footer | null = null;
pageSize(w: number, h: number) {
this._pageSize.w = w;
@ -37,6 +39,11 @@ export class SectionProperty {
this._docGrid = { gridType, linePitch, charSpace };
return this;
}
footer(footer: Footer) {
this._footer = footer;
return this;
}
}
export type PageOrientationType = "landscape" | "portrait";

View File

@ -73,6 +73,11 @@ impl Docx {
self
}
pub fn footer(mut self, footer: Footer) -> Self {
self.0 = self.0.footer(footer.take());
self
}
pub fn page_size(mut self, w: u32, h: u32) -> Docx {
self.0 = self.0.page_size(w, h);
self

View File

@ -0,0 +1,30 @@
use super::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
#[derive(Debug)]
pub struct Footer(docx_rs::Footer);
#[wasm_bindgen(js_name = createFooter)]
pub fn create_footer() -> Footer {
Footer(docx_rs::Footer::new())
}
impl Footer {
pub fn take(self) -> docx_rs::Footer {
self.0
}
}
#[wasm_bindgen]
impl Footer {
pub fn add_paragraph(mut self, p: Paragraph) -> Self {
self.0 = self.0.add_paragraph(p.take());
self
}
pub fn add_table(mut self, t: Table) -> Self {
self.0 = self.0.add_table(t.take());
self
}
}

View File

@ -3,6 +3,7 @@ mod adaptors;
mod comment;
mod delete;
mod doc;
mod footer;
mod insert;
mod level;
mod level_override;
@ -23,6 +24,7 @@ pub use adaptors::*;
pub use comment::*;
pub use delete::*;
pub use doc::*;
pub use footer::*;
pub use insert::*;
pub use level::*;
pub use level_override::*;

View File

@ -10,6 +10,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -134,6 +135,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -157,11 +159,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -383,6 +387,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -793,6 +798,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -816,11 +822,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -1716,6 +1724,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -2260,6 +2269,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -2283,11 +2293,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": true,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -2509,6 +2521,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -4778,6 +4791,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -4801,11 +4815,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -5399,6 +5415,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -5676,6 +5693,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -5699,11 +5717,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -5925,6 +5945,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -6363,6 +6384,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -6386,11 +6408,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -9711,6 +9735,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -10948,6 +10973,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -10971,11 +10997,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": true,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -13718,6 +13746,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -14245,6 +14274,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -14268,11 +14298,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -18168,6 +18200,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -19018,6 +19051,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -19041,11 +19075,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -19793,6 +19829,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -20303,6 +20340,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -20326,11 +20364,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -21060,6 +21100,7 @@ Object {
},
"contentType": Object {
"custom_xml_count": 1,
"footer_count": 1,
"types": Object {
"/_rels/.rels": "application/vnd.openxmlformats-package.relationships+xml",
"/docProps/app.xml": "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -21366,6 +21407,7 @@ Object {
"gridType": "lines",
"linePitch": 360,
},
"footerReference": null,
"headerReference": Object {
"headerType": "default",
"id": "rId4",
@ -21389,11 +21431,13 @@ Object {
},
"documentRels": Object {
"customXmlCount": 0,
"footerCount": 0,
"hasComments": false,
"hasNumberings": false,
"imageIds": Array [],
},
"fontTable": Object {},
"footer": null,
"header": Object {
"children": Array [],
},
@ -22162,6 +22206,30 @@ exports[`writer should write doc vars 3`] = `
</w:num></w:numbering>"
`;
exports[`writer should write footer for default section 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=\\"rId4\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\\" Target=\\"header1.xml\\" />
<Relationship Id=\\"rId5\\" Type=\\"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\\" Target=\\"commentsExtended.xml\\" />
<Relationship Id=\\"rIdFooter1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer\\" Target=\\"footer1.xml\\" />
</Relationships>"
`;
exports[`writer should write footer for default section 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:rFonts /></w:rPr><w:t xml:space=\\"preserve\\">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:headerReference w:type=\\"default\\" r:id=\\"rId4\\" /><w:cols w:space=\\"425\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /><w:footerReference w:type=\\"default\\" r:id=\\"rIdFooter1\\" /></w:sectPr></w:body>
</w:document>"
`;
exports[`writer should write footer for default section 3`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?>
<w:ftr 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\\"><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr><w:rFonts /></w:rPr><w:t xml:space=\\"preserve\\">Hello Footer</w:t></w:r></w:p></w:ftr>"
`;
exports[`writer should write hello 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">

View File

@ -362,4 +362,18 @@ describe("writer", () => {
}
}
});
test("should write footer for default section", () => {
const p1 = new w.Paragraph().addRun(new w.Run().addText("Hello Footer"));
const p2 = new w.Paragraph().addRun(new w.Run().addText("World "));
const footer = new w.Footer().addParagraph(p1);
const buffer = new w.Docx().footer(footer).addParagraph(p2).build();
writeFileSync("../output/footer.docx", buffer);
const z = new Zip(Buffer.from(buffer));
for (const e of z.getEntries()) {
if (e.entryName.match(/document.xml|footer1.xml/)) {
expect(z.readAsText(e)).toMatchSnapshot();
}
}
});
});