feat: Add styles
parent
16ecf4ec8c
commit
f5f089c54e
|
@ -55,6 +55,8 @@ impl BuildXML for ContentTypes {
|
|||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
use crate::documents::BuildXML;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
pub struct Color {
|
||||
val: String,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn new(val: impl Into<String>) -> Color {
|
||||
Color { val: val.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Color {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
XMLBuilder::new().color(&self.val).build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_build() {
|
||||
let c = Color::new("FFFFFF");
|
||||
let b = c.build();
|
||||
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:color w:val="FFFFFF" />"#);
|
||||
}
|
||||
}
|
|
@ -19,9 +19,8 @@ impl DocDefaults {
|
|||
impl BuildXML for DocDefaults {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
let run_property_default = self.run_property_default.build();
|
||||
b.open_doc_defaults()
|
||||
.add_child_buffer(&run_property_default)
|
||||
.add_child(&self.run_property_default)
|
||||
.close()
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod based_on;
|
||||
mod color;
|
||||
mod doc_defaults;
|
||||
mod name;
|
||||
mod next;
|
||||
|
@ -10,6 +11,7 @@ mod style;
|
|||
mod sz;
|
||||
|
||||
pub use based_on::*;
|
||||
pub use color::*;
|
||||
pub use doc_defaults::*;
|
||||
pub use name::*;
|
||||
pub use next::*;
|
||||
|
|
|
@ -25,6 +25,8 @@ impl BuildXML for ParagraphProperty {
|
|||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,32 +1,45 @@
|
|||
use super::Sz;
|
||||
use super::{Color, Sz};
|
||||
use crate::documents::BuildXML;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
pub struct RunProperty {
|
||||
sz: Option<Sz>,
|
||||
color: Option<Color>,
|
||||
}
|
||||
|
||||
impl RunProperty {
|
||||
pub fn new() -> RunProperty {
|
||||
RunProperty { sz: None }
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_sz(mut self, sz: Sz) -> RunProperty {
|
||||
self.sz = Some(sz);
|
||||
pub fn add_sz(mut self, sz: usize) -> RunProperty {
|
||||
self.sz = Some(Sz::new(sz));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_color(mut self, color: &str) -> RunProperty {
|
||||
self.color = Some(Color::new(color));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RunProperty {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sz: None,
|
||||
color: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for RunProperty {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
let b = b.open_run_property();
|
||||
let b = if let Some(sz) = &self.sz {
|
||||
b.add_child_buffer(&sz.build())
|
||||
} else {
|
||||
b
|
||||
};
|
||||
b.close().build()
|
||||
b.open_run_property()
|
||||
.add_optional_child(&self.sz)
|
||||
.add_optional_child(&self.color)
|
||||
.close()
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,11 +53,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_build() {
|
||||
let c = RunProperty::new().add_sz(Sz::new(10));
|
||||
let c = RunProperty::new().add_sz(10).add_color("FFFFFF");
|
||||
let b = c.build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:rPr><w:sz w:val="10" /></w:rPr>"#
|
||||
r#"<w:rPr><w:sz w:val="10" /><w:color w:val="FFFFFF" /></w:rPr>"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,8 @@ impl RunPropertyDefault {
|
|||
impl BuildXML for RunPropertyDefault {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
let run_property = self.run_property.build();
|
||||
b.open_run_property_default()
|
||||
.add_child_buffer(&run_property)
|
||||
.add_child(&self.run_property)
|
||||
.close()
|
||||
.build()
|
||||
}
|
||||
|
@ -28,6 +27,8 @@ impl BuildXML for RunPropertyDefault {
|
|||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -11,18 +11,14 @@ pub struct Style {
|
|||
paragraph_property: ParagraphProperty,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn new(
|
||||
style_id: impl Into<String>,
|
||||
name: impl Into<String>,
|
||||
style_type: StyleType,
|
||||
) -> Style {
|
||||
let name = Name::new(name.into());
|
||||
impl Default for Style {
|
||||
fn default() -> Style {
|
||||
let name = Name::new("");
|
||||
let rpr = RunProperty::new();
|
||||
let ppr = ParagraphProperty::new();
|
||||
Style {
|
||||
style_id: style_id.into(),
|
||||
style_type,
|
||||
style_id: "".to_owned(),
|
||||
style_type: StyleType::Paragraph,
|
||||
name,
|
||||
run_property: rpr,
|
||||
paragraph_property: ppr,
|
||||
|
@ -30,22 +26,34 @@ impl Style {
|
|||
}
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn new(
|
||||
style_id: impl Into<String>,
|
||||
name: impl Into<String>,
|
||||
style_type: StyleType,
|
||||
) -> Style {
|
||||
let name = Name::new(name.into());
|
||||
let default = Default::default();
|
||||
Style {
|
||||
style_id: style_id.into(),
|
||||
style_type,
|
||||
name,
|
||||
..default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Style {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
let name = self.name.build();
|
||||
let rpr = self.run_property.build();
|
||||
let ppr = self.paragraph_property.build();
|
||||
let based_on = BasedOn::new("Normal").build();
|
||||
let next = Next::new("Normal").build();
|
||||
let q_format = QFormat::new().build();
|
||||
// Set "Normal" as default if you need change these values please fix it
|
||||
b.open_style(self.style_type, &self.style_id)
|
||||
.add_child_buffer(&name)
|
||||
.add_child_buffer(&rpr)
|
||||
.add_child_buffer(&ppr)
|
||||
.add_child_buffer(&based_on)
|
||||
.add_child_buffer(&next)
|
||||
.add_child_buffer(&q_format)
|
||||
.add_child(&self.name)
|
||||
.add_child(&self.run_property)
|
||||
.add_child(&self.paragraph_property)
|
||||
.add_child(&BasedOn::new("Normal"))
|
||||
.add_child(&Next::new("Normal"))
|
||||
.add_child(&QFormat::new())
|
||||
.close()
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -3,14 +3,17 @@ mod content_types;
|
|||
mod doc_props;
|
||||
mod elements;
|
||||
mod rels;
|
||||
mod styles;
|
||||
mod xml_document;
|
||||
|
||||
pub(crate) use build_xml::*;
|
||||
|
||||
use crate::xml_builder::*;
|
||||
use content_types::*;
|
||||
use doc_props::*;
|
||||
use elements::*;
|
||||
use rels::*;
|
||||
use styles::*;
|
||||
|
||||
pub(crate) struct Document {
|
||||
content_type: ContentTypes,
|
||||
|
|
|
@ -39,6 +39,8 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use std::str;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_build() {
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
use crate::documents::BuildXML;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
use super::{DocDefaults, Style, StyleType};
|
||||
|
||||
pub struct Styles {
|
||||
doc_defaults: DocDefaults,
|
||||
styles: Vec<Style>,
|
||||
}
|
||||
|
||||
impl Styles {
|
||||
pub fn new() -> Styles {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_style(mut self, style: Style) -> Self {
|
||||
self.styles.push(style);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Styles {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
doc_defaults: DocDefaults::new(),
|
||||
styles: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Styles {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
b.open_styles()
|
||||
.add_child(&self.doc_defaults)
|
||||
.add_children(&self.styles)
|
||||
.close()
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_build() {
|
||||
let c = Styles::new().add_style(Style::new("Title", "TitleName", StyleType::Paragraph));
|
||||
let b = c.build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15"><w:docDefaults><w:rPrDefault><w:rPr /></w:rPrDefault></w:docDefaults><w:style w:type="paragraph" w:styleId="Title"><w:name w:val="TitleName" /><w:rPr /><w:pPr /><w:basedOn w:val="Normal" /><w:next w:val="Normal" /><w:qFormat /></w:style></w:styles>"#
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
use super::XMLBuilder;
|
||||
use super::XmlEvent;
|
||||
|
||||
impl XMLBuilder {
|
||||
// i.e. <w:color ... >
|
||||
pub(crate) fn color(mut self, val: &str) -> Self {
|
||||
self.writer
|
||||
.write(XmlEvent::start_element("w:color").attr("w:val", val))
|
||||
.expect("should write to buf");
|
||||
self.close()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_color() {
|
||||
let b = XMLBuilder::new();
|
||||
let r = b.color("2E74B5").build();
|
||||
assert_eq!(str::from_utf8(&r).unwrap(), r#"<w:color w:val="2E74B5" />"#);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
mod macros;
|
||||
|
||||
mod based_on;
|
||||
mod color;
|
||||
mod doc_defaults;
|
||||
mod name;
|
||||
mod next;
|
||||
|
@ -13,6 +14,7 @@ mod style;
|
|||
mod sz;
|
||||
|
||||
pub use based_on::*;
|
||||
pub use color::*;
|
||||
pub use doc_defaults::*;
|
||||
pub use name::*;
|
||||
pub use next::*;
|
||||
|
|
|
@ -6,7 +6,9 @@ mod declaration;
|
|||
mod elements;
|
||||
mod properties;
|
||||
mod relationship;
|
||||
mod styles;
|
||||
|
||||
use crate::BuildXML;
|
||||
use std::str;
|
||||
use xml::common::XmlVersion;
|
||||
use xml::writer::{EmitterConfig, EventWriter, XmlEvent};
|
||||
|
@ -50,12 +52,36 @@ impl XMLBuilder {
|
|||
self.close()
|
||||
}
|
||||
|
||||
pub(crate) fn add_child_buffer(mut self, buf: &[u8]) -> Self {
|
||||
let text = str::from_utf8(buf).unwrap();
|
||||
pub(crate) fn add_child<T>(mut self, child: &T) -> Self
|
||||
where
|
||||
T: BuildXML,
|
||||
{
|
||||
let buf = child.build();
|
||||
let text = str::from_utf8(&buf).unwrap();
|
||||
self.writer.write(text).expect("should write to buf");
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn add_optional_child<T>(mut self, child: &Option<T>) -> Self
|
||||
where
|
||||
T: BuildXML,
|
||||
{
|
||||
if let Some(c) = child {
|
||||
self = self.add_child(c)
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn add_children<T>(mut self, children: &[T]) -> Self
|
||||
where
|
||||
T: BuildXML,
|
||||
{
|
||||
for c in children {
|
||||
self = self.add_child(c);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
// Close tag
|
||||
pub(crate) fn close(mut self) -> Self {
|
||||
self.writer
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
use std::fmt;
|
||||
|
||||
use super::XMLBuilder;
|
||||
use super::XmlEvent;
|
||||
|
||||
impl XMLBuilder {
|
||||
// Build w:style element
|
||||
// i.e. <w:styles ... >
|
||||
pub(crate) fn open_styles(mut self) -> Self {
|
||||
self.writer
|
||||
.write(
|
||||
XmlEvent::start_element("w:styles")
|
||||
.attr(
|
||||
"xmlns:mc",
|
||||
"http://schemas.openxmlformats.org/markup-compatibility/2006",
|
||||
)
|
||||
.attr(
|
||||
"xmlns:r",
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||
)
|
||||
.attr(
|
||||
"xmlns:w",
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
)
|
||||
.attr(
|
||||
"xmlns:w14",
|
||||
"http://schemas.microsoft.com/office/word/2010/wordml",
|
||||
)
|
||||
.attr(
|
||||
"xmlns:w15",
|
||||
"http://schemas.microsoft.com/office/word/2012/wordml",
|
||||
)
|
||||
.attr("mc:Ignorable", "w14 w15"),
|
||||
)
|
||||
.expect("should write to buf");
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_declaration() {
|
||||
let b = XMLBuilder::new();
|
||||
let r = b.open_styles().close().build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&r).unwrap(),
|
||||
r#"<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15" />"#
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue