feat: Support styleWithLevels (#403)

main
bokuweb 2022-01-11 00:39:38 +09:00 committed by GitHub
parent e888af2545
commit cdb91be925
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 144 additions and 15 deletions

View File

@ -18,7 +18,8 @@ pub fn main() -> Result<(), DocxError> {
.add_table_of_contents( .add_table_of_contents(
TableOfContents::new() TableOfContents::new()
.heading_styles_range(1, 3) .heading_styles_range(1, 3)
.alias("Table of contents"), .alias("Table of contents")
.auto(),
) )
.add_paragraph(p1) .add_paragraph(p1)
.add_paragraph(p2) .add_paragraph(p2)

View File

@ -0,0 +1,49 @@
use docx_rs::*;
pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./output/examples/toc_with_style_level.docx");
let file = std::fs::File::create(&path).unwrap();
let style1 = Style::new("Heading1", StyleType::Paragraph).name("Heading 1");
let style2 = Style::new("StyleLevel1", StyleType::Paragraph)
.name("Style Level1")
.based_on("Heading1");
let style3 = Style::new("StyleLevel4", StyleType::Paragraph)
.name("Style Level4")
.based_on("Heading4");
let style4 = Style::new("Heading4", StyleType::Paragraph).name("Heading 4");
let p1 = Paragraph::new()
.add_run(Run::new().add_text("Hello"))
.style("Heading1")
.page_break_before(true);
let p2 = Paragraph::new()
.add_run(Run::new().add_text("Foo"))
.style("StyleLevel1")
.page_break_before(true);
let p3 = Paragraph::new()
.add_run(Run::new().add_text("Bar"))
.style("StyleLevel4")
.page_break_before(true);
Docx::new()
.add_style(style1)
.add_style(style2)
.add_style(style3)
.add_style(style4)
.add_table_of_contents(
TableOfContents::new()
.heading_styles_range(1, 3)
.add_style_with_level(StyleWithLevel::new("StyleLevel1", 1))
.add_style_with_level(StyleWithLevel::new("StyleLevel4", 4))
.alias("Table of contents")
.auto(),
)
.add_paragraph(p1)
.add_paragraph(p2)
.add_paragraph(p3)
.build()
.pack(file)?;
Ok(())
}

View File

@ -26,6 +26,11 @@ impl TableOfContents {
self self
} }
pub fn add_style_with_level(mut self, s: StyleWithLevel) -> Self {
self.instr = self.instr.add_style_with_level(s);
self
}
pub fn hyperlink(mut self) -> Self { pub fn hyperlink(mut self) -> Self {
self.instr = self.instr.hyperlink(); self.instr = self.instr.hyperlink();
self self

View File

@ -873,6 +873,19 @@ fn update_document_by_toc(
let heading_map = styles.create_heading_style_map(); let heading_map = styles.create_heading_style_map();
let mut items = vec![]; let mut items = vec![];
let mut children = vec![]; let mut children = vec![];
let style_map: std::collections::HashMap<String, usize> = toc
.instr
.styles_with_levels
.iter()
.map(|sl| sl.0.clone())
.collect();
if toc.instr.heading_styles_range.is_none() && !toc.instr.styles_with_levels.is_empty() {
// INFO: if \t option set without heading styles ranges, Microsoft word does not show ToC items...
return document_children;
}
let (min, max) = toc.instr.heading_styles_range.unwrap_or((0, 9));
for child in document_children.into_iter() { for child in document_children.into_iter() {
match child { match child {
@ -884,20 +897,7 @@ fn update_document_by_toc(
.map(|p| p.val.to_string()) .map(|p| p.val.to_string())
.and_then(|sid| heading_map.get(&sid)) .and_then(|sid| heading_map.get(&sid))
{ {
if let Some((min, max)) = toc.instr.heading_styles_range {
if min <= *heading_level && max >= *heading_level { if min <= *heading_level && max >= *heading_level {
let toc_key = TocKey::generate();
items.push(
TableOfContentsItem::new()
.text(paragraph.raw_text())
.toc_key(&toc_key)
.level(*heading_level),
);
paragraph =
paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key);
}
} else {
// If no heading range is specified, all heading levels used in the document are listed.
let toc_key = TocKey::generate(); let toc_key = TocKey::generate();
items.push( items.push(
TableOfContentsItem::new() TableOfContentsItem::new()
@ -912,6 +912,26 @@ fn update_document_by_toc(
// TODO: check tc field // TODO: check tc field
} }
} }
// Support \t option. Collect toc items if style id matched.
if let Some(level) = paragraph
.property
.style
.as_ref()
.and_then(|s| style_map.get(&s.val))
{
if min <= *level && max >= *level {
let toc_key = TocKey::generate();
items.push(
TableOfContentsItem::new()
.text(paragraph.raw_text())
.toc_key(&toc_key)
.level(*level),
);
paragraph = paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key);
}
}
children.push(DocumentChild::Paragraph(paragraph)); children.push(DocumentChild::Paragraph(paragraph));
} }
DocumentChild::Table(ref _table) => { DocumentChild::Table(ref _table) => {

View File

@ -38,6 +38,28 @@ export class Style {
return this; return this;
}; };
basedOn = (n: string) => {
this._basedOn = n;
return this;
};
// TODO:
// runProperty = (n: RunProperty) => {
// this._runProperty = n;
// return this;
// };
// TODO:
// paragraphProperty = (n: ParagraphProperty) => {
// this._paragraphProperty = n;
// return this;
// };
tableProperty = (n: TableProperty) => {
this._tableProperty = n;
return this;
};
buildStyleType = () => { buildStyleType = () => {
switch (this._styleType) { switch (this._styleType) {
case "character": case "character":
@ -60,6 +82,10 @@ export class Style {
s = s.name(this._name); s = s.name(this._name);
} }
if (this._basedOn) {
s = s.based_on(this._basedOn);
}
return s; return s;
}; };
} }

View File

@ -4,6 +4,7 @@ import { TableOfContentsItem } from "./table-of-contents-item";
export class TableOfContents { export class TableOfContents {
_headingStylesRange: [number, number] | null = null; _headingStylesRange: [number, number] | null = null;
_styleWithLevels: { styleId: string; level: number }[] = [];
_hyperlink = false; _hyperlink = false;
_alias = ""; _alias = "";
_auto = false; _auto = false;
@ -16,6 +17,11 @@ export class TableOfContents {
return this; return this;
}; };
addStyleWithLevel = (styleId: string, level: number) => {
this._styleWithLevels.push({ styleId, level });
return this;
};
hyperlink = () => { hyperlink = () => {
this._hyperlink = true; this._hyperlink = true;
return this; return this;
@ -75,6 +81,10 @@ export class TableOfContents {
toc = toc.page_ref_placeholder(this._pageRefPlaceholder); toc = toc.page_ref_placeholder(this._pageRefPlaceholder);
} }
for (const sl of this._styleWithLevels) {
toc = toc.add_style_with_level(sl.styleId, sl.level);
}
for (const item of this._items) { for (const item of this._items) {
toc = toc.add_item(item.buildWasmObject()); toc = toc.add_item(item.buildWasmObject());
} }

View File

@ -81,6 +81,16 @@ impl Style {
self self
} }
// pub fn run_property(mut self, p: docx_rs::RunProperty) -> Self {
// self.0.run_property = p;
// self
// }
// pub fn paragraph_property(mut self, p: docx_rs::ParagraphProperty) -> Self {
// self.0.paragraph_property = p;
// self
// }
pub fn table_property(mut self, p: docx_rs::TableProperty) -> Self { pub fn table_property(mut self, p: docx_rs::TableProperty) -> Self {
self.0.table_property = p; self.0.table_property = p;
self self

View File

@ -24,6 +24,14 @@ impl TableOfContents {
self self
} }
pub fn add_style_with_level(mut self, style: &str, level: usize) -> Self {
self.0.instr = self
.0
.instr
.add_style_with_level(docx_rs::StyleWithLevel::new(style, level));
self
}
pub fn hyperlink(mut self) -> Self { pub fn hyperlink(mut self) -> Self {
self.0.instr = self.0.instr.hyperlink(); self.0.instr = self.0.instr.hyperlink();
self self

View File