Support font and paragraph prop (#81)

* feat: Add run fonts

* feat: Fix run property in pPr

* feat: Add js interface

* fix: lint error
main
bokuweb 2020-06-08 13:41:13 +09:00 committed by GitHub
parent 9265986b63
commit 00aecc91e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 474 additions and 125 deletions

View File

@ -77,6 +77,7 @@ writeFileSync("hello.docx", buf);
- [Minimum](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/hello.rs)
- [Indent](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/indent.rs)
- [Alignment](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/alignment.rs)
- [Font](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/font.rs)
- [Numbering](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/numbering.rs)
- [Table](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/table.rs)
- [Comment](https://github.com/bokuweb/docx-rs/blob/master/docx-core/examples/comment.rs)
@ -92,6 +93,7 @@ writeFileSync("hello.docx", buf);
- [x] Run
- [x] Bold
- [x] Size
- [x] Font
- [x] Color
- [x] Highlight
- [x] Underline

View File

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

View File

@ -59,7 +59,7 @@ mod tests {
);
assert_eq!(
serde_json::to_string(&graphic).unwrap(),
r#"{"children":[{"dataType":"wpShape","children":[{"type":"shape","data":{"children":[{"type":"textbox","data":{"children":[{"children":[{"type":"paragraph","data":{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"pattern1"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}}],"has_numbering":false}],"hasNumbering":false}}]}}]}]}"#
r#"{"children":[{"dataType":"wpShape","children":[{"type":"shape","data":{"children":[{"type":"textbox","data":{"children":[{"children":[{"type":"paragraph","data":{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"pattern1"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}}],"has_numbering":false}],"hasNumbering":false}}]}}]}]}"#
);
}
}

View File

@ -90,7 +90,7 @@ mod tests {
.num_style_link("style1");
assert_eq!(
serde_json::to_string(&c).unwrap(),
r#"{"id":0,"styleLink":null,"numStyleLink":"style1","levels":[{"level":1,"start":1,"format":"decimal","text":"%4.","jc":"left","pstyle":null,"paragraphProperty":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"suffix":"tab"}]}"#
r#"{"id":0,"styleLink":null,"numStyleLink":"style1","levels":[{"level":1,"start":1,"format":"decimal","text":"%4.","jc":"left","pstyle":null,"paragraphProperty":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"suffix":"tab"}]}"#
);
}
}

View File

@ -35,15 +35,16 @@ mod next;
mod number_format;
mod numbering;
mod numbering_id;
mod pic;
mod numbering_property;
mod page_margin;
mod page_size;
mod paragraph;
mod paragraph_property;
mod paragraph_style;
mod pic;
mod q_format;
mod run;
mod run_fonts;
mod run_property;
mod run_property_default;
mod section_property;
@ -53,6 +54,7 @@ mod sz;
mod sz_cs;
mod tab;
mod table;
mod table_borders;
mod table_cell;
mod table_cell_borders;
mod table_cell_margins;
@ -61,7 +63,6 @@ mod table_cell_width;
mod table_grid;
mod table_indent;
mod table_property;
mod table_borders;
mod table_row;
mod table_row_property;
mod table_width;
@ -119,8 +120,10 @@ pub use page_size::*;
pub use paragraph::*;
pub use paragraph_property::*;
pub use paragraph_style::*;
pub use pic::*;
pub use q_format::*;
pub use run::*;
pub use run_fonts::*;
pub use run_property::*;
pub use run_property_default::*;
pub use section_property::*;
@ -131,7 +134,6 @@ pub use sz_cs::*;
pub use tab::*;
pub use table::*;
pub use table_borders::*;
pub use pic::*;
pub use table_cell::*;
pub use table_cell_borders::*;
pub use table_cell_margins::*;

View File

@ -28,7 +28,7 @@ impl Default for Paragraph {
#[derive(Debug, Clone, PartialEq)]
pub enum ParagraphChild {
Run(Run),
Run(Box<Run>),
Insert(Insert),
Delete(Delete),
BookmarkStart(BookmarkStart),
@ -107,7 +107,7 @@ impl Paragraph {
}
pub fn add_run(mut self, run: Run) -> Paragraph {
self.children.push(ParagraphChild::Run(run));
self.children.push(ParagraphChild::Run(Box::new(run)));
self
}
@ -177,6 +177,31 @@ impl Paragraph {
self.has_numbering = true;
self
}
pub fn size(mut self, size: usize) -> Self {
self.property.run_property = self.property.run_property.size(size);
self
}
pub fn bold(mut self) -> Self {
self.property.run_property = self.property.run_property.bold();
self
}
pub fn italic(mut self) -> Self {
self.property.run_property = self.property.run_property.italic();
self
}
pub fn fonts(mut self, f: RunFonts) -> Self {
self.property.run_property = self.property.run_property.fonts(f);
self
}
pub(crate) fn run_property(mut self, p: RunProperty) -> Self {
self.property.run_property = p;
self
}
}
impl BuildXML for Paragraph {
@ -271,7 +296,7 @@ mod tests {
let p = Paragraph::new().add_run(run);
assert_eq!(
serde_json::to_string(&p).unwrap(),
r#"{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}"#
r#"{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}"#
);
}
@ -282,7 +307,7 @@ mod tests {
let p = Paragraph::new().add_insert(ins);
assert_eq!(
serde_json::to_string(&p).unwrap(),
r#"{"children":[{"type":"insert","data":{"runs":[{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}]}],"author":"unnamed","date":"1970-01-01T00:00:00Z"}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}"#
r#"{"children":[{"type":"insert","data":{"runs":[{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}]}],"author":"unnamed","date":"1970-01-01T00:00:00Z"}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}"#
);
}
}

View File

@ -90,10 +90,7 @@ mod tests {
fn test_default() {
let c = ParagraphProperty::new();
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:pPr><w:rPr /></w:pPr>"#
);
assert_eq!(str::from_utf8(&b).unwrap(), r#"<w:pPr><w:rPr /></w:pPr>"#);
}
#[test]
@ -122,7 +119,7 @@ mod tests {
let b = c.indent(Some(20), Some(SpecialIndentType::FirstLine(10)), None, None);
assert_eq!(
serde_json::to_string(&b).unwrap(),
r#"{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":null,"numberingProperty":null,"alignment":null,"indent":{"start":20,"startChars":null,"end":null,"specialIndent":{"type":"firstLine","val":10}}}"#
r#"{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"style":null,"numberingProperty":null,"alignment":null,"indent":{"start":20,"startChars":null,"end":null,"specialIndent":{"type":"firstLine","val":10}}}"#
);
}
}

View File

@ -157,6 +157,11 @@ impl Run {
self.run_property = self.run_property.vanish();
self
}
pub fn fonts(mut self, f: RunFonts) -> Run {
self.run_property = self.run_property.fonts(f);
self
}
}
impl BuildXML for Run {
@ -231,11 +236,12 @@ mod tests {
italic: Some(Italic::new()),
italic_cs: Some(ItalicCs::new()),
vanish: Some(Vanish::new()),
fonts: None,
},
};
assert_eq!(
serde_json::to_string(&run).unwrap(),
r#"{"runProperty":{"sz":30,"szCs":30,"color":"C9211E","highlight":"yellow","underline":"single","bold":true,"boldCs":true,"italic":true,"italicCs":true,"vanish":true},"children":[{"type":"tab"},{"type":"text","data":{"preserveSpace":true,"text":"Hello"}},{"type":"break","data":{"breakType":"page"}},{"type":"deleteText","data":{"text":"deleted","preserveSpace":true}}]}"#
r#"{"runProperty":{"sz":30,"szCs":30,"color":"C9211E","highlight":"yellow","underline":"single","bold":true,"boldCs":true,"italic":true,"italicCs":true,"vanish":true,"fonts":null},"children":[{"type":"tab"},{"type":"text","data":{"preserveSpace":true,"text":"Hello"}},{"type":"break","data":{"breakType":"page"}},{"type":"deleteText","data":{"text":"deleted","preserveSpace":true}}]}"#
);
}
}

View File

@ -0,0 +1,108 @@
use serde::{Deserialize, Serialize};
use crate::documents::BuildXML;
use crate::xml_builder::*;
/*
17.3.2.26 rFonts (Run Fonts)
This element specifies the fonts which shall be used to display the text contents of this run.
Within a single run, there can be up to four types of font slot which shall each be allowed to use a unique font:
- ASCII (i.e., the first 128 Unicode code points)
- High ANSI
- Complex Script
*/
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct RunFonts {
ascii: Option<String>,
hi_ansi: Option<String>,
east_asia: Option<String>,
cs: Option<String>,
}
impl RunFonts {
pub fn new() -> RunFonts {
Default::default()
}
pub fn ascii(mut self, f: impl Into<String>) -> Self {
self.ascii = Some(f.into());
self
}
pub fn hi_ansi(mut self, f: impl Into<String>) -> Self {
self.hi_ansi = Some(f.into());
self
}
pub fn east_asia(mut self, f: impl Into<String>) -> Self {
self.east_asia = Some(f.into());
self
}
pub fn cs(mut self, f: impl Into<String>) -> Self {
self.cs = Some(f.into());
self
}
}
impl BuildXML for RunFonts {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
b.run_fonts(
self.ascii.as_ref(),
self.hi_ansi.as_ref(),
self.cs.as_ref(),
self.east_asia.as_ref(),
)
.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(test)]
use pretty_assertions::assert_eq;
use std::str;
#[test]
fn test_run_fonts_east_asia_build() {
let c = RunFonts::new().east_asia("Hiragino");
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:rFonts w:eastAsia="Hiragino" />"#
);
}
#[test]
fn test_run_fonts_ascii_build() {
let c = RunFonts::new().ascii("Arial");
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:rFonts w:ascii="Arial" />"#
);
}
#[test]
fn test_run_fonts_hi_ansi_build() {
let c = RunFonts::new().hi_ansi("Arial");
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:rFonts w:hAnsi="Arial" />"#
);
}
#[test]
fn test_run_fonts_cs_build() {
let c = RunFonts::new().cs("Arial");
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:rFonts w:cs="Arial" />"#
);
}
}

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use super::{Bold, BoldCs, Color, Highlight, Italic, ItalicCs, Sz, SzCs, Underline, Vanish};
use super::*;
use crate::documents::BuildXML;
use crate::xml_builder::*;
@ -17,6 +17,7 @@ pub struct RunProperty {
pub italic: Option<Italic>,
pub italic_cs: Option<ItalicCs>,
pub vanish: Option<Vanish>,
pub fonts: Option<RunFonts>,
}
impl RunProperty {
@ -61,6 +62,11 @@ impl RunProperty {
self.vanish = Some(Vanish::new());
self
}
pub fn fonts(mut self, font: RunFonts) -> RunProperty {
self.fonts = Some(font);
self
}
}
impl Default for RunProperty {
@ -76,6 +82,7 @@ impl Default for RunProperty {
italic: None,
italic_cs: None,
vanish: None,
fonts: None,
}
}
}
@ -94,6 +101,7 @@ impl BuildXML for RunProperty {
.add_optional_child(&self.highlight)
.add_optional_child(&self.underline)
.add_optional_child(&self.vanish)
.add_optional_child(&self.fonts)
.close()
.build()
}
@ -156,4 +164,14 @@ mod tests {
r#"<w:rPr><w:vanish /></w:rPr>"#
);
}
#[test]
fn test_run_fonts() {
let c = RunProperty::new().fonts(RunFonts::new().east_asia("Hiragino"));
let b = c.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:rPr><w:rFonts w:eastAsia="Hiragino" /></w:rPr>"#
);
}
}

View File

@ -146,7 +146,7 @@ mod tests {
.grid_span(2);
assert_eq!(
serde_json::to_string(&c).unwrap(),
r#"{"children":[{"type":"paragraph","data":{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}}],"property":{"width":null,"borders":null,"gridSpan":2,"verticalMerge":null,"verticalAlign":null},"hasNumbering":false}"#
r#"{"children":[{"type":"paragraph","data":{"children":[{"type":"run","data":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"children":[{"type":"text","data":{"preserveSpace":true,"text":"Hello"}}]}}],"property":{"runProperty":{"sz":null,"szCs":null,"color":null,"highlight":null,"underline":null,"bold":null,"boldCs":null,"italic":null,"italicCs":null,"vanish":null,"fonts":null},"style":null,"numberingProperty":null,"alignment":null,"indent":null},"hasNumbering":false,"attrs":[]}}],"property":{"width":null,"borders":null,"gridSpan":2,"verticalMerge":null,"verticalAlign":null},"hasNumbering":false}"#
);
}
}

View File

@ -9,6 +9,7 @@ mod errors;
mod from_xml;
mod insert;
mod level;
mod level_override;
mod mc_fallback;
mod numbering_property;
mod numberings;
@ -16,6 +17,7 @@ mod paragraph;
mod read_zip;
mod rels;
mod run;
mod run_property;
mod style;
mod styles;
mod table;
@ -27,7 +29,6 @@ mod wp_anchor;
mod wps_shape;
mod wps_text_box;
mod xml_element;
mod level_override;
use std::io::Cursor;

View File

@ -99,6 +99,11 @@ impl ElementReader for Paragraph {
}
continue;
}
XMLElement::RunProperty => {
let run_pr = RunProperty::read(r, attrs)?;
p = p.run_property(run_pr);
continue;
}
_ => {}
}
}
@ -142,7 +147,7 @@ mod tests {
assert_eq!(
p,
Paragraph {
children: vec![ParagraphChild::Run(Run::new().add_text("a"))],
children: vec![ParagraphChild::Run(Box::new(Run::new().add_text("a")))],
property: ParagraphProperty {
run_property: RunProperty::new(),
style: None,
@ -181,7 +186,7 @@ mod tests {
assert_eq!(
p,
Paragraph {
children: vec![ParagraphChild::Run(Run::new().add_text("a"))],
children: vec![ParagraphChild::Run(Box::new(Run::new().add_text("a")))],
property: ParagraphProperty {
run_property: RunProperty::new(),
style: None,
@ -348,7 +353,7 @@ mod tests {
Paragraph {
children: vec![
ParagraphChild::BookmarkStart(BookmarkStart::new(0, "ABCD-1234")),
ParagraphChild::Run(Run::new().add_text("Bookmarked")),
ParagraphChild::Run(Box::new(Run::new().add_text("Bookmarked"))),
ParagraphChild::BookmarkEnd(BookmarkEnd::new(0)),
],
property: ParagraphProperty {

View File

@ -38,6 +38,7 @@ impl ElementReader for Run {
XMLElement::Tab => {
run = run.add_tab();
}
// TODO: use RunProperty::read()
XMLElement::Bold => {
if !read_bool(&attributes) {
continue;
@ -147,13 +148,7 @@ mod tests {
sz: Some(Sz::new(30)),
sz_cs: Some(SzCs::new(30)),
color: Some(Color::new("C9211E")),
highlight: None,
underline: None,
bold: None,
bold_cs: None,
italic: None,
italic_cs: None,
vanish: None,
..RunProperty::default()
},
}
);
@ -170,18 +165,7 @@ mod tests {
run,
Run {
children: vec![RunChild::Tab(Tab::new())],
run_property: RunProperty {
sz: None,
sz_cs: None,
color: None,
highlight: None,
underline: None,
bold: None,
bold_cs: None,
italic: None,
italic_cs: None,
vanish: None,
},
run_property: RunProperty::default(),
}
);
}
@ -197,18 +181,7 @@ mod tests {
run,
Run {
children: vec![RunChild::Break(Break::new(BreakType::Page))],
run_property: RunProperty {
sz: None,
sz_cs: None,
color: None,
highlight: None,
underline: None,
bold: None,
bold_cs: None,
italic: None,
italic_cs: None,
vanish: None,
},
run_property: RunProperty::default(),
}
);
}
@ -224,18 +197,7 @@ mod tests {
run,
Run {
children: vec![RunChild::Break(Break::new(BreakType::TextWrapping))],
run_property: RunProperty {
sz: None,
sz_cs: None,
color: None,
highlight: None,
underline: None,
bold: None,
bold_cs: None,
italic: None,
italic_cs: None,
vanish: None,
},
run_property: RunProperty::default(),
}
);
}
@ -255,16 +217,9 @@ mod tests {
Run {
children: vec![],
run_property: RunProperty {
sz: None,
sz_cs: None,
color: None,
highlight: None,
underline: None,
bold: Some(Bold::new()),
bold_cs: Some(BoldCs::new()),
italic: None,
italic_cs: None,
vanish: None,
..RunProperty::default()
},
}
);
@ -285,16 +240,9 @@ mod tests {
Run {
children: vec![],
run_property: RunProperty {
sz: None,
sz_cs: None,
color: None,
highlight: None,
underline: None,
bold: Some(Bold::new()),
bold_cs: Some(BoldCs::new()),
italic: None,
italic_cs: None,
vanish: None,
..RunProperty::default()
},
}
);

View File

@ -0,0 +1,55 @@
use std::io::Read;
use std::str::FromStr;
use xml::attribute::OwnedAttribute;
use xml::reader::{EventReader, XmlEvent};
use super::*;
impl ElementReader for RunProperty {
fn read<R: Read>(
r: &mut EventReader<R>,
_attrs: &[OwnedAttribute],
) -> Result<Self, ReaderError> {
let mut rp = RunProperty::new();
loop {
let e = r.next();
match e {
Ok(XmlEvent::StartElement {
attributes, name, ..
}) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
match e {
XMLElement::Bold => {
if !read_bool(&attributes) {
continue;
}
rp = rp.bold();
}
XMLElement::Highlight => rp = rp.highlight(attributes[0].value.clone()),
XMLElement::Color => rp = rp.color(attributes[0].value.clone()),
XMLElement::Size => rp = rp.size(usize::from_str(&attributes[0].value)?),
XMLElement::Underline => rp = rp.underline(&attributes[0].value.clone()),
XMLElement::Italic => {
if !read_bool(&attributes) {
continue;
}
rp = rp.italic();
}
XMLElement::Vanish => rp = rp.vanish(),
// TODO: Add run fonts reader
_ => {}
}
}
Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap();
if e == XMLElement::RunProperty {
return Ok(rp);
}
}
Err(_) => return Err(ReaderError::XMLReadError),
_ => {}
}
}
}
}

View File

@ -22,6 +22,31 @@ impl XMLBuilder {
self.writer.write(text).expect(EXPECT_MESSAGE);
self.close()
}
pub(crate) fn run_fonts(
mut self,
ascii: Option<&String>,
hi_ansi: Option<&String>,
cs: Option<&String>,
east_asia: Option<&String>,
) -> Self {
let mut w = XmlEvent::start_element("w:rFonts");
if let Some(ascii) = ascii {
w = w.attr("w:ascii", ascii);
}
if let Some(hi_ansi) = hi_ansi {
w = w.attr("w:hAnsi", hi_ansi);
}
if let Some(cs) = cs {
w = w.attr("w:cs", cs);
}
if let Some(east_asia) = east_asia {
w = w.attr("w:eastAsia", east_asia);
}
self.writer.write(w).expect(EXPECT_MESSAGE);
self.close()
}
// i.e. <w:delText ... >
pub(crate) fn delete_text(mut self, text: &str, preserve_space: bool) -> Self {
let space = if preserve_space {

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

@ -235,6 +235,39 @@ export class Docx {
paragraph = paragraph.style(p.property.styleId);
}
if (p.property.runProperty.bold) {
paragraph = paragraph.bold();
}
if (p.property.runProperty.bold) {
paragraph = paragraph.bold();
}
if (p.property.runProperty.italic) {
paragraph = paragraph.italic();
}
if (p.property.runProperty.size) {
paragraph = paragraph.size(p.property.runProperty.size);
}
if (p.property.runProperty.fonts) {
let f = wasm.createRunFonts();
if (p.property.runProperty.fonts.ascii) {
f = f.ascii(p.property.runProperty.fonts.ascii);
}
if (p.property.runProperty.fonts.hiAnsi) {
f = f.hi_ansi(p.property.runProperty.fonts.hiAnsi);
}
if (p.property.runProperty.fonts.cs) {
f = f.cs(p.property.runProperty.fonts.cs);
}
if (p.property.runProperty.fonts.eastAsia) {
f = f.east_asia(p.property.runProperty.fonts.eastAsia);
}
paragraph = paragraph.fonts(f);
}
return paragraph;
}

View File

@ -14,7 +14,7 @@ export type NumberingPropertyJSON = {
};
export type ParagraphPropertyJSON = {
runProperty: RunChildJSON;
runProperty: RunPropertyJSON;
style: string | null;
numberingProperty: NumberingPropertyJSON | null;
alignment: "left" | "center" | "right" | "justified" | "both";

View File

@ -8,7 +8,7 @@ export class Level {
format: string;
text: string;
jc: string;
paragraphProperty: ParagraphProperty = {};
paragraphProperty: ParagraphProperty = { runProperty: {} };
levelSuffix: LevelSuffixType;
constructor(

View File

@ -1,4 +1,4 @@
import { Run } from "./run";
import { Run, RunProperty, RunFonts } from "./run";
import { Insert } from "./insert";
import { Delete } from "./delete";
import { BookmarkStart } from "./bookmark-start";
@ -31,12 +31,15 @@ export type ParagraphProperty = {
id: number;
level: number;
};
runProperty: RunProperty;
};
export class Paragraph {
hasNumberings = false;
children: ParagraphChild[] = [];
property: ParagraphProperty = {};
property: ParagraphProperty = {
runProperty: {},
};
addRun(run: Run) {
this.children.push(run);
@ -97,4 +100,25 @@ export class Paragraph {
this.property.numbering = { id, level };
return this;
}
// run property
size(size: number) {
this.property.runProperty = { ...this.property.runProperty, size };
return this;
}
bold() {
this.property.runProperty = { ...this.property.runProperty, bold: true };
return this;
}
italic() {
this.property.runProperty = { ...this.property.runProperty, italic: true };
return this;
}
fonts(fonts: RunFonts) {
this.property.runProperty = { ...this.property.runProperty, fonts };
return this;
}
}

View File

@ -13,6 +13,14 @@ export type RunProperty = {
italic?: boolean;
underline?: string;
vanish?: boolean;
fonts?: RunFonts;
};
export type RunFonts = {
ascii?: string;
hiAnsi?: string;
eastAsia?: string;
cs?: string;
};
export class Run {
@ -73,4 +81,9 @@ export class Run {
this.property = { ...this.property, vanish: true };
return this;
}
fonts(fonts: RunFonts) {
this.property = { ...this.property, fonts };
return this;
}
}

View File

@ -10,10 +10,11 @@ mod numbering;
mod paragraph;
mod reader;
mod run;
mod run_fonts;
mod table;
mod table_cell;
mod table_row;
mod table_cell_border;
mod table_row;
pub use abstract_numbering::*;
pub use adaptors::*;
@ -27,7 +28,7 @@ pub use numbering::*;
pub use paragraph::*;
pub use reader::*;
pub use run::*;
pub use run_fonts::*;
pub use table::*;
pub use table_cell::*;
pub use table_row::*;
pub use table_cell_border::*;
pub use table_cell_border::*;pub use table_row::*;

View File

@ -91,6 +91,26 @@ impl Paragraph {
self.0.property = self.0.property.numbering(id, level);
self
}
pub fn size(mut self, size: usize) -> Self {
self.0 = self.0.size(size);
self
}
pub fn bold(mut self) -> Self {
self.0 = self.0.bold();
self
}
pub fn italic(mut self) -> Self {
self.0 = self.0.italic();
self
}
pub fn fonts(mut self, f: RunFonts) -> Self {
self.0 = self.0.fonts(f.take());
self
}
}
impl Paragraph {

View File

@ -1,3 +1,4 @@
use super::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
@ -19,12 +20,16 @@ impl Run {
pub fn add_delete_text(mut self, text: &str) -> Run {
self.0
.children
.push(docx_rs::RunChild::DeleteText(docx_rs::DeleteText::new(text)));
.push(docx_rs::RunChild::DeleteText(docx_rs::DeleteText::new(
text,
)));
self
}
pub fn add_tab(mut self) -> Run {
self.0.children.push(docx_rs::RunChild::Tab(docx_rs::Tab::new()));
self.0
.children
.push(docx_rs::RunChild::Tab(docx_rs::Tab::new()));
self
}
@ -69,6 +74,11 @@ impl Run {
self.0.run_property = self.0.run_property.vanish();
self
}
pub fn fonts(mut self, f: RunFonts) -> Self {
self.0 = self.0.fonts(f.take());
self
}
}
impl Run {

View File

@ -0,0 +1,39 @@
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
#[derive(Debug)]
pub struct RunFonts(docx_rs::RunFonts);
#[wasm_bindgen(js_name = createRunFonts)]
pub fn create_run_fonts() -> RunFonts {
RunFonts(docx_rs::RunFonts::new())
}
impl RunFonts {
pub fn take(self) -> docx_rs::RunFonts {
self.0
}
}
#[wasm_bindgen]
impl RunFonts {
pub fn ascii(mut self, f: String) -> Self {
self.0 = self.0.ascii(f);
self
}
pub fn hi_ansi(mut self, f: String) -> Self {
self.0 = self.0.hi_ansi(f);
self
}
pub fn cs(mut self, f: String) -> Self {
self.0 = self.0.cs(f);
self
}
pub fn east_asia(mut self, f: String) -> Self {
self.0 = self.0.east_asia(f);
self
}
}