Fix comment structure (#216)

* fix: Add comment children

* feat: Update snaps

* fix: specs

* spec: Add spec

* fix: js if
main
bokuweb 2020-12-21 17:30:42 +09:00 committed by GitHub
parent e45e0431e9
commit 2e5a22fc53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 3952 additions and 249 deletions

View File

@ -10,7 +10,7 @@ pub fn main() -> Result<(), DocxError> {
Comment::new(1) Comment::new(1)
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z") .date("2019-01-01T00:00:00Z")
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
) )
.add_comment_end(1), .add_comment_end(1),
) )

View File

@ -10,7 +10,8 @@ pub fn main() -> Result<(), DocxError> {
Comment::new(1) Comment::new(1)
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z") .date("2019-01-01T00:00:00Z")
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello")))
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("World"))),
) )
.add_comment_end(1) .add_comment_end(1)
.add_comment_start( .add_comment_start(
@ -18,7 +19,7 @@ pub fn main() -> Result<(), DocxError> {
.author("bokuweb") .author("bokuweb")
.date("2019-01-02T00:00:00Z") .date("2019-01-02T00:00:00Z")
.parent_comment_id(1) .parent_comment_id(1)
.paragraph(Paragraph::new().add_run(Run::new().add_text("World"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("World"))),
) )
.add_comment_end(2) .add_comment_end(2)
.add_comment_start( .add_comment_start(
@ -26,7 +27,8 @@ pub fn main() -> Result<(), DocxError> {
.author("bokuweb") .author("bokuweb")
.date("2019-01-02T00:00:00Z") .date("2019-01-02T00:00:00Z")
.parent_comment_id(1) .parent_comment_id(1)
.paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!")))
.add_paragraph(Paragraph::new().add_run(Run::new().add_text("!!!!!"))),
) )
.add_comment_end(3), .add_comment_end(3),
) )

View File

@ -1,6 +1,7 @@
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize; use serde::Serialize;
use crate::documents::{BuildXML, Paragraph}; use crate::documents::*;
use crate::xml_builder::*; use crate::xml_builder::*;
#[derive(Serialize, Debug, Clone, PartialEq)] #[derive(Serialize, Debug, Clone, PartialEq)]
@ -9,17 +10,45 @@ pub struct Comment {
pub id: usize, pub id: usize,
pub author: String, pub author: String,
pub date: String, pub date: String,
pub paragraph: Paragraph, pub children: Vec<CommentChild>,
pub parent_comment_id: Option<usize>, pub parent_comment_id: Option<usize>,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum CommentChild {
Paragraph(Paragraph),
Table(Table),
}
impl Serialize for CommentChild {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
CommentChild::Paragraph(ref p) => {
let mut t = serializer.serialize_struct("Paragraph", 2)?;
t.serialize_field("type", "paragraph")?;
t.serialize_field("data", p)?;
t.end()
}
CommentChild::Table(ref c) => {
let mut t = serializer.serialize_struct("Table", 2)?;
t.serialize_field("type", "table")?;
t.serialize_field("data", c)?;
t.end()
}
}
}
}
impl Default for Comment { impl Default for Comment {
fn default() -> Comment { fn default() -> Comment {
Comment { Comment {
id: 1, id: 1,
author: "unnamed".to_owned(), author: "unnamed".to_owned(),
date: "1970-01-01T00:00:00Z".to_owned(), date: "1970-01-01T00:00:00Z".to_owned(),
paragraph: Paragraph::new(), children: vec![],
parent_comment_id: None, parent_comment_id: None,
} }
} }
@ -43,8 +72,13 @@ impl Comment {
self self
} }
pub fn paragraph(mut self, p: Paragraph) -> Comment { pub fn add_paragraph(mut self, p: Paragraph) -> Self {
self.paragraph = p; self.children.push(CommentChild::Paragraph(p));
self
}
pub fn add_table(mut self, t: Table) -> Self {
self.children.push(CommentChild::Table(t));
self self
} }
@ -58,11 +92,20 @@ impl Comment {
} }
} }
impl BuildXML for CommentChild {
fn build(&self) -> Vec<u8> {
match self {
CommentChild::Paragraph(v) => v.build(),
CommentChild::Table(v) => v.build(),
}
}
}
impl BuildXML for Comment { impl BuildXML for Comment {
fn build(&self) -> Vec<u8> { fn build(&self) -> Vec<u8> {
XMLBuilder::new() XMLBuilder::new()
.open_comment(&format!("{}", self.id), &self.author, &self.date, "") .open_comment(&format!("{}", self.id), &self.author, &self.date, "")
.add_child(&self.paragraph) .add_children(&self.children)
.close() .close()
.build() .build()
} }
@ -77,8 +120,17 @@ mod tests {
use std::str; use std::str;
#[test] #[test]
fn test_ins_default() { fn test_comment_default() {
let b = Comment::new(1).build(); 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="" />"#
);
}
#[test]
fn test_comment_with_default_paragraph() {
let b = Comment::new(1).add_paragraph(Paragraph::new()).build();
assert_eq!( assert_eq!(
str::from_utf8(&b).unwrap(), 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 w14:paraId="12345678"><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>"#

View File

@ -278,8 +278,14 @@ impl Docx {
for child in &paragraph.children { for child in &paragraph.children {
if let ParagraphChild::CommentStart(c) = child { if let ParagraphChild::CommentStart(c) = child {
let comment = c.get_comment(); let comment = c.get_comment();
let para_id = comment.paragraph.id.clone(); let comment_id = comment.id();
comment_map.insert(comment.id(), para_id.clone()); for child in comment.children {
if let CommentChild::Paragraph(child) = child {
let para_id = child.id.clone();
comment_map.insert(comment_id, para_id.clone());
}
// TODO: Support table
}
} }
} }
} }
@ -292,8 +298,15 @@ impl Docx {
for child in &paragraph.children { for child in &paragraph.children {
if let ParagraphChild::CommentStart(c) = child { if let ParagraphChild::CommentStart(c) = child {
let comment = c.get_comment(); let comment = c.get_comment();
let para_id = comment.paragraph.id.clone(); let comment_id = comment.id();
comment_map.insert(comment.id(), para_id.clone()); for child in comment.children {
if let CommentChild::Paragraph(child) = child {
let para_id = child.id.clone();
comment_map
.insert(comment_id, para_id.clone());
}
// TODO: Support table
}
} }
} }
} }
@ -312,18 +325,24 @@ impl Docx {
for child in &paragraph.children { for child in &paragraph.children {
if let ParagraphChild::CommentStart(c) = child { if let ParagraphChild::CommentStart(c) = child {
let comment = c.get_comment(); let comment = c.get_comment();
let para_id = comment.paragraph.id.clone(); for child in comment.children {
if let CommentChild::Paragraph(child) = child {
let para_id = child.id.clone();
comments.push(c.get_comment()); comments.push(c.get_comment());
let comment_extended = CommentExtended::new(para_id); let comment_extended = CommentExtended::new(para_id);
if let Some(parent_comment_id) = comment.parent_comment_id { if let Some(parent_comment_id) = comment.parent_comment_id {
let parent_para_id = let parent_para_id =
comment_map.get(&parent_comment_id).unwrap().clone(); comment_map.get(&parent_comment_id).unwrap().clone();
comments_extended comments_extended.push(
.push(comment_extended.parent_paragraph_id(parent_para_id)); comment_extended.parent_paragraph_id(parent_para_id),
);
} else { } else {
comments_extended.push(comment_extended); comments_extended.push(comment_extended);
} }
} }
// TODO: Support table
}
}
} }
} }
DocumentChild::Table(table) => { DocumentChild::Table(table) => {
@ -335,7 +354,9 @@ impl Docx {
for child in &paragraph.children { for child in &paragraph.children {
if let ParagraphChild::CommentStart(c) = child { if let ParagraphChild::CommentStart(c) = child {
let comment = c.get_comment(); let comment = c.get_comment();
let para_id = comment.paragraph.id.clone(); for child in comment.children {
if let CommentChild::Paragraph(child) = child {
let para_id = child.id.clone();
comments.push(c.get_comment()); comments.push(c.get_comment());
let comment_extended = let comment_extended =
CommentExtended::new(para_id); CommentExtended::new(para_id);
@ -348,10 +369,15 @@ impl Docx {
.clone(); .clone();
comments_extended.push( comments_extended.push(
comment_extended comment_extended
.parent_paragraph_id(parent_para_id), .parent_paragraph_id(
parent_para_id,
),
); );
} else { } else {
comments_extended.push(comment_extended); comments_extended
.push(comment_extended);
}
}
} }
} }
} }

View File

@ -29,7 +29,7 @@ impl ElementReader for Comment {
.expect("should convert to XMLElement"); .expect("should convert to XMLElement");
if let XMLElement::Paragraph = e { if let XMLElement::Paragraph = e {
let p = Paragraph::read(r, &attributes)?; let p = Paragraph::read(r, &attributes)?;
comment = comment.paragraph(p); comment = comment.add_paragraph(p);
} }
} }
Ok(XmlEvent::EndElement { name, .. }) => { Ok(XmlEvent::EndElement { name, .. }) => {

View File

@ -126,19 +126,31 @@ pub fn read_docx(buf: &[u8]) -> Result<Docx, ReaderError> {
let mut comments = Comments::from_xml(&data[..])?.into_inner(); let mut comments = Comments::from_xml(&data[..])?.into_inner();
for i in 0..comments.len() { for i in 0..comments.len() {
let c = &comments[i]; let c = &comments[i];
let extended = comments_extended let extended = comments_extended.children.iter().find(|ex| {
.children for child in &c.children {
.iter() if let CommentChild::Paragraph(p) = child {
.find(|ex| ex.paragraph_id == c.paragraph.id); if ex.paragraph_id == p.id {
return true;
}
}
}
false
});
if let Some(CommentExtended { if let Some(CommentExtended {
parent_paragraph_id: Some(parent_paragraph_id), parent_paragraph_id: Some(parent_paragraph_id),
.. ..
}) = extended }) = extended
{ {
if let Some(parent_comment) = comments if let Some(parent_comment) = comments.iter().find(|c| {
.iter() for child in &c.children {
.find(|c| &c.paragraph.id == parent_paragraph_id) if let CommentChild::Paragraph(p) = child {
{ if &p.id == parent_paragraph_id {
return true;
}
}
}
false
}) {
comments[i].parent_comment_id = Some(parent_comment.id); comments[i].parent_comment_id = Some(parent_comment.id);
} }
} }

View File

@ -262,7 +262,7 @@ pub fn comments() -> Result<(), DocxError> {
Comment::new(1) Comment::new(1)
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z") .date("2019-01-01T00:00:00Z")
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
) )
.add_run(Run::new().add_text("Hello").highlight("cyan")) .add_run(Run::new().add_text("Hello").highlight("cyan"))
.add_run(Run::new().add_text(" World!").highlight("yellow")) .add_run(Run::new().add_text(" World!").highlight("yellow"))
@ -284,7 +284,7 @@ pub fn comments_to_table() -> Result<(), DocxError> {
Comment::new(1) Comment::new(1)
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z") .date("2019-01-01T00:00:00Z")
.paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Hello"))),
) )
.add_run(Run::new().add_text("Hello")) .add_run(Run::new().add_text("Hello"))
.add_comment_end(1), .add_comment_end(1),
@ -298,7 +298,7 @@ pub fn comments_to_table() -> Result<(), DocxError> {
Comment::new(1) Comment::new(1)
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z") .date("2019-01-01T00:00:00Z")
.paragraph(Paragraph::new().add_run(Run::new().add_text("Comment!!"))), .add_paragraph(Paragraph::new().add_run(Run::new().add_text("Comment!!"))),
) )
.add_run(Run::new().add_text("Hello").highlight("cyan")) .add_run(Run::new().add_text("Hello").highlight("cyan"))
.add_comment_end(1), .add_comment_end(1),

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

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,11 @@
import { Paragraph } from "./paragraph"; import { Paragraph } from "./paragraph";
import { Table } from "./table";
export class Comment { export class Comment {
id: number; id: number;
_author: string; _author: string;
_date: string; _date: string;
_paragraph: Paragraph; children: (Paragraph | Table)[] = [];
_parentCommentId: number; _parentCommentId: number;
constructor(id: number) { constructor(id: number) {
@ -21,8 +22,8 @@ export class Comment {
return this; return this;
} }
paragraph(p: Paragraph) { addParagraph(p: Paragraph) {
this._paragraph = p; this.children.push(p);
return this; return this;
} }

View File

@ -231,9 +231,13 @@ export class Docx {
buildComment(c: Comment) { buildComment(c: Comment) {
let comment = wasm.createComment(c.id); let comment = wasm.createComment(c.id);
if (c._paragraph) { c.children.forEach((child) => {
comment = comment.paragraph(this.buildParagraph(c._paragraph)); if (child instanceof Paragraph) {
comment = comment.add_paragraph(this.buildParagraph(child));
} else if (child instanceof Table) {
// TODO:
} }
});
if (c._author) { if (c._author) {
comment = comment.author(c._author); comment = comment.author(c._author);
} }

View File

@ -1,10 +1,12 @@
import { ParagraphJSON } from "../"; import { ParagraphJSON, TableJSON } from "../";
export type CommentChildJSON = ParagraphJSON | TableJSON;
export type CommentJSON = { export type CommentJSON = {
id: number; id: number;
author: string; author: string;
date: string; date: string;
paragraph: ParagraphJSON; children: CommentChildJSON[];
parentCommentId: number | null; parentCommentId: number | null;
}; };

View File

@ -28,8 +28,8 @@ impl Comment {
self self
} }
pub fn paragraph(mut self, p: Paragraph) -> Comment { pub fn add_paragraph(mut self, p: Paragraph) -> Comment {
self.0.paragraph = p.take(); self.0 = self.0.add_paragraph(p.take());
self self
} }

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,14 @@ describe("reader", () => {
const json = w.readDocx(buf); const json = w.readDocx(buf);
expect(json).toMatchSnapshot(); expect(json).toMatchSnapshot();
}); });
test("should read multi paragraph comments docx", () => {
const buf = readFileSync(
"../fixtures/multi_paragraph_comment/multi_paragraph_comment.docx"
);
const json = w.readDocx(buf);
expect(json).toMatchSnapshot();
});
}); });
describe("writer", () => { describe("writer", () => {