feat: Support custom numbering
parent
7dff9e771d
commit
182f82e9a0
|
@ -9,7 +9,7 @@ pub struct Level<'a> {
|
|||
format: NumberFormat<'a>,
|
||||
text: LevelText<'a>,
|
||||
jc: LevelJc<'a>,
|
||||
paragraph_property: ParagraphProperty<'a>,
|
||||
paragraph_property: ParagraphProperty,
|
||||
}
|
||||
|
||||
impl<'a> Level<'a> {
|
||||
|
|
|
@ -3,12 +3,12 @@ use crate::xml_builder::*;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Numbering<'a> {
|
||||
id: &'a str,
|
||||
id: usize,
|
||||
levels: Vec<Level<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Numbering<'a> {
|
||||
pub fn new(id: &'a str) -> Self {
|
||||
pub fn new(id: usize) -> Self {
|
||||
Self { id, levels: vec![] }
|
||||
}
|
||||
|
||||
|
@ -20,16 +20,13 @@ impl<'a> Numbering<'a> {
|
|||
|
||||
impl<'a> BuildXML for Numbering<'a> {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let id = format!("{}", self.id);
|
||||
let mut b = XMLBuilder::new();
|
||||
b = b.open_abstract_num(self.id);
|
||||
b = b.open_abstract_num(&id);
|
||||
for l in &self.levels {
|
||||
b = b.add_child(l);
|
||||
}
|
||||
b.close()
|
||||
.open_num(self.id)
|
||||
.abstract_num_id(self.id)
|
||||
.close()
|
||||
.build()
|
||||
b.close().open_num(&id).abstract_num_id(&id).close().build()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +41,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_numbering() {
|
||||
let mut c = Numbering::new("0");
|
||||
let mut c = Numbering::new(0);
|
||||
c = c.add_level(Level::new(
|
||||
1,
|
||||
Start::new(1),
|
||||
|
|
|
@ -2,17 +2,17 @@ use crate::documents::BuildXML;
|
|||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NumberingId<'a> {
|
||||
id: &'a str,
|
||||
pub struct NumberingId {
|
||||
id: usize,
|
||||
}
|
||||
|
||||
impl<'a> NumberingId<'a> {
|
||||
pub fn new(id: &'a str) -> NumberingId<'a> {
|
||||
impl NumberingId {
|
||||
pub fn new(id: usize) -> NumberingId {
|
||||
NumberingId { id }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BuildXML for NumberingId<'a> {
|
||||
impl BuildXML for NumberingId {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
b.num_id(self.id).build()
|
||||
|
@ -29,8 +29,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_num_id() {
|
||||
let c = NumberingId::new("abc");
|
||||
let c = NumberingId::new(0);
|
||||
let b = c.build();
|
||||
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:numId w:val="abc" />"#);
|
||||
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:numId w:val="0" />"#);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,18 +3,18 @@ use crate::documents::BuildXML;
|
|||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NumberingProperty<'a> {
|
||||
id: NumberingId<'a>,
|
||||
pub struct NumberingProperty {
|
||||
id: NumberingId,
|
||||
level: IndentLevel,
|
||||
}
|
||||
|
||||
impl<'a> NumberingProperty<'a> {
|
||||
pub fn new(id: NumberingId<'a>, level: IndentLevel) -> NumberingProperty {
|
||||
impl NumberingProperty {
|
||||
pub fn new(id: NumberingId, level: IndentLevel) -> NumberingProperty {
|
||||
Self { id, level }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BuildXML for NumberingProperty<'a> {
|
||||
impl BuildXML for NumberingProperty {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
b.open_numbering_property()
|
||||
|
@ -35,11 +35,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_num_property() {
|
||||
let c = NumberingProperty::new(NumberingId::new("abc"), IndentLevel::new(3));
|
||||
let c = NumberingProperty::new(NumberingId::new(0), IndentLevel::new(3));
|
||||
let b = c.build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:numPr><w:numId w:val="abc" /><w:ilvl w:val="3" /></w:numPr>"#
|
||||
r#"<w:numPr><w:numId w:val="0" /><w:ilvl w:val="3" /></w:numPr>"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::xml_builder::*;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Paragraph<'a> {
|
||||
pub(crate) children: Vec<ParagraphChild<'a>>,
|
||||
property: ParagraphProperty<'a>,
|
||||
property: ParagraphProperty,
|
||||
attrs: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ impl<'a> Paragraph<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn numbering(mut self, id: NumberingId<'a>, level: IndentLevel) -> Self {
|
||||
pub fn numbering(mut self, id: NumberingId, level: IndentLevel) -> Self {
|
||||
self.property = self.property.numbering(id, level);
|
||||
self
|
||||
}
|
||||
|
@ -205,11 +205,11 @@ mod tests {
|
|||
fn test_numbering() {
|
||||
let b = Paragraph::new()
|
||||
.add_run(Run::new().add_text("Hello"))
|
||||
.numbering(NumberingId::new("abc"), IndentLevel::new(1))
|
||||
.numbering(NumberingId::new(0), IndentLevel::new(1))
|
||||
.build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:p><w:pPr><w:pStyle w:val="Normal" /><w:rPr /><w:numPr><w:numId w:val="abc" /><w:ilvl w:val="1" /></w:numPr></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p>"#
|
||||
r#"<w:p><w:pPr><w:pStyle w:val="Normal" /><w:rPr /><w:numPr><w:numId w:val="0" /><w:ilvl w:val="1" /></w:numPr></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p>"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@ use crate::types::{AlignmentType, SpecialIndentType};
|
|||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParagraphProperty<'a> {
|
||||
pub struct ParagraphProperty {
|
||||
run_property: RunProperty,
|
||||
style: ParagraphStyle,
|
||||
numbering_property: Option<NumberingProperty<'a>>,
|
||||
numbering_property: Option<NumberingProperty>,
|
||||
alignment: Option<Justification>,
|
||||
indent: Option<Indent>,
|
||||
}
|
||||
|
||||
impl<'a> Default for ParagraphProperty<'a> {
|
||||
impl Default for ParagraphProperty {
|
||||
fn default() -> Self {
|
||||
let s: Option<&str> = None;
|
||||
ParagraphProperty {
|
||||
|
@ -32,8 +32,8 @@ impl<'a> Default for ParagraphProperty<'a> {
|
|||
// This element specifies a set of paragraph properties which shall be applied to the contents of the parent
|
||||
// paragraph after all style/numbering/table properties have been applied to the text. These properties are defined
|
||||
// as direct formatting, since they are directly applied to the paragraph and supersede any formatting from styles.
|
||||
impl<'a> ParagraphProperty<'a> {
|
||||
pub fn new() -> ParagraphProperty<'a> {
|
||||
impl ParagraphProperty {
|
||||
pub fn new() -> ParagraphProperty {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
|
@ -52,13 +52,13 @@ impl<'a> ParagraphProperty<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn numbering(mut self, id: NumberingId<'a>, level: IndentLevel) -> Self {
|
||||
pub fn numbering(mut self, id: NumberingId, level: IndentLevel) -> Self {
|
||||
self.numbering_property = Some(NumberingProperty::new(id, level));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BuildXML for ParagraphProperty<'a> {
|
||||
impl BuildXML for ParagraphProperty {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
XMLBuilder::new()
|
||||
.open_paragraph_property()
|
||||
|
|
|
@ -5,15 +5,15 @@ use crate::StyleType;
|
|||
use super::{BasedOn, Name, Next, ParagraphProperty, QFormat, RunProperty};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Style<'a> {
|
||||
pub struct Style {
|
||||
style_id: String,
|
||||
name: Name,
|
||||
style_type: StyleType,
|
||||
run_property: RunProperty,
|
||||
paragraph_property: ParagraphProperty<'a>,
|
||||
paragraph_property: ParagraphProperty,
|
||||
}
|
||||
|
||||
impl<'a> Default for Style<'a> {
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
let name = Name::new("");
|
||||
let rpr = RunProperty::new();
|
||||
|
@ -28,7 +28,7 @@ impl<'a> Default for Style<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Style<'a> {
|
||||
impl Style {
|
||||
pub fn new(
|
||||
style_id: impl Into<String>,
|
||||
name: impl Into<String>,
|
||||
|
@ -65,7 +65,7 @@ impl<'a> Style<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> BuildXML for Style<'a> {
|
||||
impl BuildXML for Style {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
// Set "Normal" as default if you need change these values please fix it
|
||||
|
|
|
@ -35,7 +35,7 @@ pub struct Docx<'a> {
|
|||
rels: Rels,
|
||||
document_rels: DocumentRels,
|
||||
doc_props: DocProps<'a>,
|
||||
styles: Styles<'a>,
|
||||
styles: Styles,
|
||||
document: Document<'a>,
|
||||
comments: Comments<'a>,
|
||||
numberings: Numberings<'a>,
|
||||
|
|
|
@ -37,7 +37,7 @@ impl<'a> BuildXML for Numberings<'a> {
|
|||
}
|
||||
|
||||
fn create_default_numbering() -> Numbering<'static> {
|
||||
Numbering::new("0")
|
||||
Numbering::new(0)
|
||||
.add_level(
|
||||
Level::new(
|
||||
0,
|
||||
|
|
|
@ -4,23 +4,23 @@ use crate::types::*;
|
|||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Styles<'a> {
|
||||
pub struct Styles {
|
||||
doc_defaults: DocDefaults,
|
||||
styles: Vec<Style<'a>>,
|
||||
styles: Vec<Style>,
|
||||
}
|
||||
|
||||
impl<'a> Styles<'a> {
|
||||
pub fn new() -> Styles<'a> {
|
||||
impl Styles {
|
||||
pub fn new() -> Styles {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_style(mut self, style: Style<'a>) -> Self {
|
||||
pub fn add_style(mut self, style: Style) -> Self {
|
||||
self.styles.push(style);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for Styles<'a> {
|
||||
impl Default for Styles {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
doc_defaults: DocDefaults::new(),
|
||||
|
@ -29,7 +29,7 @@ impl<'a> Default for Styles<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> BuildXML for Styles<'a> {
|
||||
impl BuildXML for Styles {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
let normal = Style::new("Normal", "Normal", StyleType::Paragraph);
|
||||
|
|
|
@ -191,7 +191,7 @@ impl XMLBuilder {
|
|||
opened_el!(open_num, "w:num", "w:numId");
|
||||
opened_el!(open_numbering_property, "w:numPr");
|
||||
only_usize_val_el!(indent_level, "w:ilvl");
|
||||
only_str_val_el!(num_id, "w:numId");
|
||||
only_usize_val_el!(num_id, "w:numId");
|
||||
only_usize_val_el!(start, "w:start");
|
||||
only_str_val_el!(number_format, "w:numFmt");
|
||||
only_str_val_el!(level_text, "w:lvlText");
|
||||
|
|
|
@ -323,22 +323,49 @@ pub fn default_numbering() -> Result<(), DocxError> {
|
|||
.add_paragraph(
|
||||
Paragraph::new()
|
||||
.add_run(Run::new().add_text("Hello"))
|
||||
.numbering(NumberingId::new("0"), IndentLevel::new(0)),
|
||||
.numbering(NumberingId::new(0), IndentLevel::new(0)),
|
||||
)
|
||||
.add_paragraph(
|
||||
Paragraph::new()
|
||||
.add_run(Run::new().add_text("World!"))
|
||||
.numbering(NumberingId::new("0"), IndentLevel::new(1)),
|
||||
.numbering(NumberingId::new(0), IndentLevel::new(1)),
|
||||
)
|
||||
.add_paragraph(
|
||||
Paragraph::new()
|
||||
.add_run(Run::new().add_text("Foooo!"))
|
||||
.numbering(NumberingId::new("0"), IndentLevel::new(2)),
|
||||
.numbering(NumberingId::new(0), IndentLevel::new(2)),
|
||||
)
|
||||
.add_paragraph(
|
||||
Paragraph::new()
|
||||
.add_run(Run::new().add_text("Bar!"))
|
||||
.numbering(NumberingId::new("0"), IndentLevel::new(3)),
|
||||
.numbering(NumberingId::new(0), IndentLevel::new(3)),
|
||||
)
|
||||
.build()
|
||||
.pack(file)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn user_numbering() -> Result<(), DocxError> {
|
||||
let path = std::path::Path::new("./tests/output/user_numbering.docx");
|
||||
let file = std::fs::File::create(&path).unwrap();
|
||||
Docx::new()
|
||||
.add_paragraph(
|
||||
Paragraph::new()
|
||||
.add_run(Run::new().add_text("Hello"))
|
||||
.numbering(NumberingId::new(2), IndentLevel::new(0)),
|
||||
)
|
||||
.add_numbering(
|
||||
Numbering::new(2).add_level(
|
||||
Level::new(
|
||||
0,
|
||||
Start::new(1),
|
||||
NumberFormat::new("decimal"),
|
||||
LevelText::new("Section %1."),
|
||||
LevelJc::new("left"),
|
||||
)
|
||||
.indent(1620, Some(SpecialIndentType::Hanging(320))),
|
||||
),
|
||||
)
|
||||
.build()
|
||||
.pack(file)?;
|
||||
|
|
Loading…
Reference in New Issue