fix: comment importing in delete (#226)

main
bokuweb 2021-01-27 19:44:29 +09:00 committed by GitHub
parent 17c669bdde
commit 9069f08791
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 487 additions and 366 deletions

View File

@ -11,7 +11,7 @@ pub fn main() -> Result<(), DocxError> {
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z"), .date("2019-01-01T00:00:00Z"),
) )
.add_delete(Delete::new(Run::new().add_delete_text("World"))), .add_delete(Delete::new().add_run(Run::new().add_delete_text("World"))),
) )
.build() .build()
.pack(file)?; .pack(file)?;

View File

@ -4,7 +4,7 @@ use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
pub fn main() { pub fn main() {
let mut file = File::open("./test.docx").unwrap(); let mut file = File::open("./commenta.docx").unwrap();
let mut buf = vec![]; let mut buf = vec![];
file.read_to_end(&mut buf).unwrap(); file.read_to_end(&mut buf).unwrap();

View File

@ -38,6 +38,13 @@ impl BuildXML for CommentRangeStart {
} }
} }
impl BuildXML for Box<CommentRangeStart> {
fn build(&self) -> Vec<u8> {
let b = XMLBuilder::new();
b.comment_range_start(&format!("{}", self.id)).build()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -1,13 +1,49 @@
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize; use serde::Serialize;
use crate::documents::{BuildXML, HistoryId, Run}; use crate::documents::*;
use crate::xml_builder::*; use crate::xml_builder::*;
#[derive(Serialize, Debug, Clone, PartialEq)] #[derive(Serialize, Debug, Clone, PartialEq)]
pub struct Delete { pub struct Delete {
pub author: String, pub author: String,
pub date: String, pub date: String,
pub runs: Vec<Run>, pub children: Vec<DeleteChild>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DeleteChild {
Run(Run),
CommentStart(Box<CommentRangeStart>),
CommentEnd(CommentRangeEnd),
}
impl Serialize for DeleteChild {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
DeleteChild::Run(ref r) => {
let mut t = serializer.serialize_struct("Run", 2)?;
t.serialize_field("type", "run")?;
t.serialize_field("data", r)?;
t.end()
}
DeleteChild::CommentStart(ref r) => {
let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
t.serialize_field("type", "commentRangeStart")?;
t.serialize_field("data", r)?;
t.end()
}
DeleteChild::CommentEnd(ref r) => {
let mut t = serializer.serialize_struct("CommentRangeEnd", 2)?;
t.serialize_field("type", "commentRangeEnd")?;
t.serialize_field("data", r)?;
t.end()
}
}
}
} }
impl Default for Delete { impl Default for Delete {
@ -15,21 +51,35 @@ impl Default for Delete {
Delete { Delete {
author: "unnamed".to_owned(), author: "unnamed".to_owned(),
date: "1970-01-01T00:00:00Z".to_owned(), date: "1970-01-01T00:00:00Z".to_owned(),
runs: vec![], children: vec![],
} }
} }
} }
impl Delete { impl Delete {
pub fn new(run: Run) -> Delete { pub fn new() -> Delete {
Self { Self {
runs: vec![run], children: vec![],
..Default::default() ..Default::default()
} }
} }
pub fn add_run(mut self, run: Run) -> Delete { pub fn add_run(mut self, run: Run) -> Delete {
self.runs.push(run); self.children.push(DeleteChild::Run(run));
self
}
pub fn add_comment_start(mut self, comment: Comment) -> Delete {
self.children
.push(DeleteChild::CommentStart(Box::new(CommentRangeStart::new(
comment,
))));
self
}
pub fn add_comment_end(mut self, id: usize) -> Delete {
self.children
.push(DeleteChild::CommentEnd(CommentRangeEnd::new(id)));
self self
} }
@ -48,11 +98,15 @@ impl HistoryId for Delete {}
impl BuildXML for Delete { impl BuildXML for Delete {
fn build(&self) -> Vec<u8> { fn build(&self) -> Vec<u8> {
XMLBuilder::new() let mut b = XMLBuilder::new().open_delete(&self.generate(), &self.author, &self.date);
.open_delete(&self.generate(), &self.author, &self.date) for c in &self.children {
.add_children(&self.runs) match c {
.close() DeleteChild::Run(t) => b = b.add_child(t),
.build() DeleteChild::CommentStart(c) => b = b.add_child(c),
DeleteChild::CommentEnd(c) => b = b.add_child(c),
}
}
b.close().build()
} }
} }
@ -66,7 +120,7 @@ mod tests {
#[test] #[test]
fn test_delete_default() { fn test_delete_default() {
let b = Delete::new(Run::new()).build(); let b = Delete::new().add_run(Run::new()).build();
assert_eq!( assert_eq!(
str::from_utf8(&b).unwrap(), str::from_utf8(&b).unwrap(),
r#"<w:del w:id="123" w:author="unnamed" w:date="1970-01-01T00:00:00Z"><w:r><w:rPr /></w:r></w:del>"# r#"<w:del w:id="123" w:author="unnamed" w:date="1970-01-01T00:00:00Z"><w:r><w:rPr /></w:r></w:del>"#

View File

@ -30,6 +30,8 @@ pub enum RunChild {
Tab(Tab), Tab(Tab),
Break(Break), Break(Break),
Drawing(Box<Drawing>), Drawing(Box<Drawing>),
CommentStart(Box<CommentRangeStart>),
CommentEnd(CommentRangeEnd),
} }
impl Serialize for RunChild { impl Serialize for RunChild {
@ -67,6 +69,18 @@ impl Serialize for RunChild {
t.serialize_field("data", s)?; t.serialize_field("data", s)?;
t.end() t.end()
} }
RunChild::CommentStart(ref r) => {
let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
t.serialize_field("type", "commentRangeStart")?;
t.serialize_field("data", r)?;
t.end()
}
RunChild::CommentEnd(ref r) => {
let mut t = serializer.serialize_struct("CommentRangeEnd", 2)?;
t.serialize_field("type", "commentRangeEnd")?;
t.serialize_field("data", r)?;
t.end()
}
} }
} }
} }
@ -180,6 +194,8 @@ impl BuildXML for Run {
RunChild::Tab(t) => b = b.add_child(t), RunChild::Tab(t) => b = b.add_child(t),
RunChild::Break(t) => b = b.add_child(t), RunChild::Break(t) => b = b.add_child(t),
RunChild::Drawing(t) => b = b.add_child(t), RunChild::Drawing(t) => b = b.add_child(t),
RunChild::CommentStart(c) => b = b.add_child(c),
RunChild::CommentEnd(c) => b = b.add_child(c),
} }
} }
b.close().build() b.close().build()

View File

@ -444,6 +444,19 @@ impl Docx {
} }
} }
} }
if let ParagraphChild::Delete(ref mut delete) = child {
for child in &mut delete.children {
if let DeleteChild::CommentStart(ref mut c) = child {
let comment_id = c.get_id();
if let Some(comment) =
comments.iter().find(|c| c.id() == comment_id)
{
let comment = comment.clone();
c.as_mut().comment(comment);
}
}
}
}
} }
} }
DocumentChild::Table(table) => { DocumentChild::Table(table) => {
@ -478,6 +491,22 @@ impl Docx {
} }
} }
} }
if let ParagraphChild::Delete(ref mut delete) = child {
for child in &mut delete.children {
if let DeleteChild::CommentStart(ref mut c) =
child
{
let comment_id = c.get_id();
if let Some(comment) = comments
.iter()
.find(|c| c.id() == comment_id)
{
let comment = comment.clone();
c.as_mut().comment(comment);
}
}
}
}
} }
} }
} }

View File

@ -11,26 +11,40 @@ impl ElementReader for Delete {
r: &mut EventReader<R>, r: &mut EventReader<R>,
attrs: &[OwnedAttribute], attrs: &[OwnedAttribute],
) -> Result<Self, ReaderError> { ) -> Result<Self, ReaderError> {
let mut runs: Vec<Run> = vec![]; let mut del = Delete::new();
loop { loop {
let e = r.next(); let e = r.next();
match e { match e {
Ok(XmlEvent::StartElement { name, .. }) => { Ok(XmlEvent::StartElement {
name, attributes, ..
}) => {
let e = XMLElement::from_str(&name.local_name) let e = XMLElement::from_str(&name.local_name)
.expect("should convert to XMLElement"); .expect("should convert to XMLElement");
if let XMLElement::Run = e { match e {
runs.push(Run::read(r, attrs)?); XMLElement::Run => {
del = del.add_run(Run::read(r, attrs)?);
}
XMLElement::CommentRangeStart => {
if let Some(id) = read(&attributes, "id") {
if let Ok(id) = usize::from_str(&id) {
let comment = Comment::new(id);
del = del.add_comment_start(comment);
}
}
}
XMLElement::CommentRangeEnd => {
if let Some(id) = read(&attributes, "id") {
if let Ok(id) = usize::from_str(&id) {
del = del.add_comment_end(id);
}
}
}
_ => {}
} }
} }
Ok(XmlEvent::EndElement { name, .. }) => { Ok(XmlEvent::EndElement { name, .. }) => {
let e = XMLElement::from_str(&name.local_name).unwrap(); let e = XMLElement::from_str(&name.local_name).unwrap();
let run = if !runs.is_empty() {
std::mem::replace(&mut runs[0], Run::new())
} else {
Run::new()
};
if e == XMLElement::Delete { if e == XMLElement::Delete {
let mut del = Delete::new(run);
for attr in attrs { for attr in attrs {
let local_name = &attr.name.local_name; let local_name = &attr.name.local_name;
if local_name == "author" { if local_name == "author" {
@ -39,11 +53,6 @@ impl ElementReader for Delete {
del = del.date(&attr.value); del = del.date(&attr.value);
} }
} }
if runs.len() > 1 {
for r in runs.into_iter().skip(1) {
del = del.add_run(r);
}
}
return Ok(del); return Ok(del);
} }
} }

View File

@ -330,7 +330,8 @@ mod tests {
Paragraph { Paragraph {
id: "12345678".to_owned(), id: "12345678".to_owned(),
children: vec![ParagraphChild::Delete( children: vec![ParagraphChild::Delete(
Delete::new(Run::new().add_delete_text("Hello ")) Delete::new()
.add_run(Run::new().add_delete_text("Hello "))
.author("unknown") .author("unknown")
.date("2019-11-15T14:19:04Z") .date("2019-11-15T14:19:04Z")
)], )],

View File

@ -218,7 +218,7 @@ pub fn history() -> Result<(), DocxError> {
.author("bokuweb") .author("bokuweb")
.date("2019-01-01T00:00:00Z"), .date("2019-01-01T00:00:00Z"),
) )
.add_delete(Delete::new(Run::new().add_delete_text("World"))), .add_delete(Delete::new().add_run(Run::new().add_delete_text("World"))),
) )
.build() .build()
.pack(file)?; .pack(file)?;

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,4 +1,4 @@
import { RunJSON, RunChildJSON, RunPropertyJSON } from "./run"; import { RunJSON, RunPropertyJSON } from "./run";
import { IndentJSON } from "./indent"; import { IndentJSON } from "./indent";
import { CommentRangeStartJSON, CommentRangeEndJSON } from ".."; import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
@ -51,15 +51,17 @@ export type InsertJSON = {
export type DeleteJSON = { export type DeleteJSON = {
type: "delete"; type: "delete";
data: { data: {
runs: { children: DeleteChildJSON[];
runProperty: RunPropertyJSON;
children: RunChildJSON[];
}[];
author: string; author: string;
data: string; data: string;
}; };
}; };
export type DeleteChildJSON =
| RunJSON
| CommentRangeStartJSON
| CommentRangeEndJSON;
export type BookmarkStartJSON = { export type BookmarkStartJSON = {
type: "bookmarkStart"; type: "bookmarkStart";
data: { data: {

View File

@ -1,4 +1,5 @@
import { DrawingJSON } from "./drawing"; import { DrawingJSON } from "./drawing";
import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
export type RunPropertyJSON = { export type RunPropertyJSON = {
sz: number | null; sz: number | null;
@ -19,7 +20,9 @@ export type RunChildJSON =
| DeleteTextJSON | DeleteTextJSON
| TabJSON | TabJSON
| BreakJSON | BreakJSON
| DrawingJSON; | DrawingJSON
| CommentRangeStartJSON
| CommentRangeEndJSON;
export type TextJSON = { export type TextJSON = {
type: "text"; type: "text";

View File

@ -7,7 +7,7 @@ pub struct Delete(docx_rs::Delete);
#[wasm_bindgen(js_name = createDelete)] #[wasm_bindgen(js_name = createDelete)]
pub fn create_delete(run: Run) -> Delete { pub fn create_delete(run: Run) -> Delete {
Delete(docx_rs::Delete::new(run.take())) Delete(docx_rs::Delete::new().add_run(run.take()))
} }
impl Delete { impl Delete {