feat: Support styleWithLevels (#403)
parent
e888af2545
commit
cdb91be925
|
@ -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)
|
||||||
|
|
|
@ -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(())
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue