Skip to content

Commit

Permalink
Support nest comment (#116)
Browse files Browse the repository at this point in the history
* fix: Prepare extended comments

* feat: Append paraId for paragraph

* feat: Support comment extended

* chore: Add fixture

* fix: browser example

* fix: test

* update snaps
  • Loading branch information
bokuweb authored Aug 13, 2020
1 parent c0aab13 commit 7db426a
Show file tree
Hide file tree
Showing 82 changed files with 1,115 additions and 137 deletions.
2 changes: 1 addition & 1 deletion docx-core/examples/comment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use docx_rs::*;

pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./comment.docx");
let path = std::path::Path::new("./output/comment.docx");
let file = std::fs::File::create(&path).unwrap();
Docx::new()
.add_paragraph(
Expand Down
36 changes: 36 additions & 0 deletions docx-core/examples/nested_comment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use docx_rs::*;

pub fn main() -> Result<(), DocxError> {
let path = std::path::Path::new("./output/nested_comment.docx");
let file = std::fs::File::create(&path).unwrap();
Docx::new()
.add_paragraph(
Paragraph::new()
.add_comment_start(
Comment::new(1)
.author("bokuweb")
.date("2019-01-01T00:00:00Z")
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
)
.add_comment_end(1)
.add_comment_start(
Comment::new(2)
.author("bokuweb")
.date("2019-01-02T00:00:00Z")
.parent_comment_id(1)
.paragraph(Paragraph::new().add_run(Run::new().add_text("World"))),
)
.add_comment_end(2)
.add_comment_start(
Comment::new(3)
.author("bokuweb")
.date("2019-01-02T00:00:00Z")
.parent_comment_id(1)
.paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!"))),
)
.add_comment_end(3),
)
.build()
.pack(file)?;
Ok(())
}
57 changes: 57 additions & 0 deletions docx-core/src/documents/comments_extended.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use serde::Serialize;

use super::*;
use crate::documents::BuildXML;
use crate::xml_builder::*;

// i.e. <w15:commentEx w15:paraId="00000001" w15:paraIdParent="57D1BD7C" w15:done="0"/>

#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CommentsExtended {
children: Vec<CommentExtended>,
}

impl CommentsExtended {
pub fn new() -> CommentsExtended {
Default::default()
}

pub fn add_comments_extended(&mut self, c: Vec<CommentExtended>) {
self.children = c;
}
}

impl Default for CommentsExtended {
fn default() -> Self {
Self { children: vec![] }
}
}

impl BuildXML for CommentsExtended {
fn build(&self) -> Vec<u8> {
let mut b = XMLBuilder::new();
b = b.open_comments_extended();

for c in &self.children {
b = b.add_child(c)
}
b.close().build()
}
}

#[cfg(test)]
mod tests {

use super::*;
use insta::assert_snapshot;
use std::str;

#[test]
fn test_settings() {
let mut c = CommentsExtended::new();
c.add_comments_extended(vec![CommentExtended::new("123")]);
let b = c.build();
assert_snapshot!("comments_extended_snapshot", str::from_utf8(&b).unwrap());
}
}
5 changes: 5 additions & 0 deletions docx-core/src/documents/content_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ impl ContentTypes {
"/word/header1.xml".to_owned(),
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml".to_owned(),
);
self.types.insert(
"/word/commentsExtended.xml".to_owned(),
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml"
.to_owned(),
);
self
}
}
Expand Down
4 changes: 2 additions & 2 deletions docx-core/src/documents/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ mod tests {
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14 wp14">
<w:body><w:p><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:headerReference w:type="default" r:id="rId4" /><w:cols w:space="425" />
<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 wp14">
<w:body><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="11906" w:h="16838" /><w:pgMar w:top="1985" w:right="1701" w:bottom="1701" w:left="1701" w:header="851" w:footer="992" w:gutter="0" /><w:headerReference w:type="default" r:id="rId4" /><w:cols w:space="425" />
<w:docGrid w:type="lines" w:linePitch="360" />
</w:sectPr></w:body>
</w:document>"#
Expand Down
9 changes: 7 additions & 2 deletions docx-core/src/documents/document_rels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,24 @@ impl BuildXML for DocumentRels {
"rId4",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
"header1.xml",
)
.relationship(
"rId5",
"http://schemas.microsoft.com/office/2011/relationships/commentsExtended",
"commentsExtended.xml",
);

if self.has_comments {
b = b.relationship(
"rId5",
"rId6",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
"comments.xml",
)
}

if self.has_numberings {
b = b.relationship(
"rId6",
"rId7",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
"numbering.xml",
)
Expand Down
2 changes: 1 addition & 1 deletion docx-core/src/documents/elements/a_graphic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,"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}}]}}]}]}"#
r#"{"children":[{"dataType":"wpShape","children":[{"type":"shape","data":{"children":[{"type":"textbox","data":{"children":[{"children":[{"type":"paragraph","data":{"id":"12345678","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}}],"has_numbering":false}],"hasNumbering":false}}]}}]}]}"#
);
}
}
9 changes: 8 additions & 1 deletion docx-core/src/documents/elements/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct Comment {
pub author: String,
pub date: String,
pub paragraph: Paragraph,
pub parent_comment_id: Option<usize>,
}

impl Default for Comment {
Expand All @@ -18,6 +19,7 @@ impl Default for Comment {
author: "unnamed".to_owned(),
date: "1970-01-01T00:00:00Z".to_owned(),
paragraph: Paragraph::new(),
parent_comment_id: None,
}
}
}
Expand Down Expand Up @@ -45,6 +47,11 @@ impl Comment {
self
}

pub fn parent_comment_id(mut self, parent_comment_id: usize) -> Comment {
self.parent_comment_id = Some(parent_comment_id);
self
}

pub fn id(&self) -> usize {
self.id
}
Expand Down Expand Up @@ -73,7 +80,7 @@ mod tests {
let b = Comment::new(1).build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:comment w:id="1" w:author="unnamed" w:date="1970-01-01T00:00:00Z" w:initials=""><w:p><w:pPr><w:rPr /></w:pPr></w:p></w:comment>"#
r#"<w:comment w:id="1" w:author="unnamed" w:date="1970-01-01T00:00:00Z" w:initials=""><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr></w:p></w:comment>"#
);
}
}
40 changes: 40 additions & 0 deletions docx-core/src/documents/elements/comment_extended.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use serde::Serialize;

use crate::documents::BuildXML;
use crate::xml_builder::*;

#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CommentExtended {
paragraph_id: String,
done: bool,
parent_paragraph_id: Option<String>,
}

impl CommentExtended {
pub fn new(paragraph_id: impl Into<String>) -> CommentExtended {
Self {
paragraph_id: paragraph_id.into(),
done: false,
parent_paragraph_id: None,
}
}

pub fn done(mut self) -> CommentExtended {
self.done = true;
self
}

pub fn parent_paragraph_id(mut self, id: impl Into<String>) -> CommentExtended {
self.parent_paragraph_id = Some(id.into());
self
}
}

impl BuildXML for CommentExtended {
fn build(&self) -> Vec<u8> {
XMLBuilder::new()
.comment_extended(&self.paragraph_id, self.done, &self.parent_paragraph_id)
.build()
}
}
2 changes: 2 additions & 0 deletions docx-core/src/documents/elements/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod bookmark_start;
mod br;
mod color;
mod comment;
mod comment_extended;
mod comment_range_end;
mod comment_range_start;
mod default_tab_stop;
Expand Down Expand Up @@ -89,6 +90,7 @@ pub use bookmark_start::*;
pub use br::*;
pub use color::*;
pub use comment::*;
pub use comment_extended::*;
pub use comment_range_end::*;
pub use comment_range_start::*;
pub use default_tab_stop::*;
Expand Down
35 changes: 9 additions & 26 deletions docx-core/src/documents/elements/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ use crate::xml_builder::*;
#[derive(Serialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Paragraph {
pub id: String,
pub children: Vec<ParagraphChild>,
pub property: ParagraphProperty,
pub has_numbering: bool,
pub attrs: Vec<(String, String)>,
}

impl Default for Paragraph {
fn default() -> Self {
Self {
id: crate::generate_para_id(),
children: Vec::new(),
property: ParagraphProperty::new(),
has_numbering: false,
attrs: Vec::new(),
}
}
}
Expand Down Expand Up @@ -121,11 +121,6 @@ impl Paragraph {
self
}

pub fn add_attr(mut self, key: impl Into<String>, val: impl Into<String>) -> Paragraph {
self.attrs.push((key.into(), val.into()));
self
}

pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Paragraph {
self.children
.push(ParagraphChild::BookmarkStart(BookmarkStart::new(id, name)));
Expand Down Expand Up @@ -207,7 +202,7 @@ impl Paragraph {
impl BuildXML for Paragraph {
fn build(&self) -> Vec<u8> {
XMLBuilder::new()
.open_paragraph(&self.attrs)
.open_paragraph(&self.id)
.add_child(&self.property)
.add_children(&self.children)
.close()
Expand All @@ -230,19 +225,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:p><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p>"#
);
}

#[test]
fn test_custom_attr() {
let b = Paragraph::new()
.add_run(Run::new().add_text("Hello"))
.add_attr("customId", "abcd-1234-567890")
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:p customId="abcd-1234-567890"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p>"#
r#"<w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p>"#
);
}

Expand All @@ -255,7 +238,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:p><w:pPr><w:rPr /></w:pPr><w:bookmarkStart w:id="0" w:name="article" /><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r><w:bookmarkEnd w:id="0" /></w:p>"#
r#"<w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:bookmarkStart w:id="0" w:name="article" /><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r><w:bookmarkEnd w:id="0" /></w:p>"#
);
}

Expand All @@ -268,7 +251,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:p><w:pPr><w:rPr /></w:pPr><w:commentRangeStart w:id="1" /><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r><w:r>
r#"<w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:commentRangeStart w:id="1" /><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r><w:r>
<w:rPr />
</w:r>
<w:commentRangeEnd w:id="1" />
Expand All @@ -286,7 +269,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:p><w:pPr><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>"#
r#"<w:p w14:paraId="12345678"><w:pPr><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>"#
);
}

Expand All @@ -296,7 +279,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,"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":[]}"#
r#"{"id":"12345678","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}"#
);
}

Expand All @@ -307,7 +290,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,"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":[]}"#
r#"{"id":"12345678","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}"#
);
}
}
4 changes: 2 additions & 2 deletions docx-core/src/documents/elements/table_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:tc><w:tcPr /><w:p><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p></w:tc>"#
r#"<w:tc><w:tcPr /><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space="preserve">Hello</w:t></w:r></w:p></w:tc>"#
);
}

Expand All @@ -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,"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}"#
r#"{"children":[{"type":"paragraph","data":{"id":"12345678","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}}],"property":{"width":null,"borders":null,"gridSpan":2,"verticalMerge":null,"verticalAlign":null},"hasNumbering":false}"#
);
}
}
2 changes: 1 addition & 1 deletion docx-core/src/documents/elements/text_box_content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ mod tests {
.build();
assert_eq!(
str::from_utf8(&b).unwrap(),
r#"<w:txbxContent><w:p><w:pPr><w:rPr /></w:pPr></w:p></w:txbxContent>"#
r#"<w:txbxContent><w:p w14:paraId="12345678"><w:pPr><w:rPr /></w:pPr></w:p></w:txbxContent>"#
);
}
}
Loading

0 comments on commit 7db426a

Please sign in to comment.