2021-07-13 12:46:15 +03:00
|
|
|
use std::{collections::HashMap, str::FromStr};
|
2020-08-13 19:57:59 +03:00
|
|
|
|
2022-01-02 19:18:04 +02:00
|
|
|
mod bookmark_id;
|
2019-11-06 05:29:17 +02:00
|
|
|
mod build_xml;
|
2019-12-04 10:39:59 +02:00
|
|
|
mod comments;
|
2020-08-13 19:57:59 +03:00
|
|
|
mod comments_extended;
|
2019-11-05 11:03:23 +02:00
|
|
|
mod content_types;
|
2021-07-13 12:46:15 +03:00
|
|
|
mod custom_item;
|
|
|
|
mod custom_item_property;
|
|
|
|
mod custom_item_rels;
|
2019-11-05 12:20:40 +02:00
|
|
|
mod doc_props;
|
2019-11-07 09:08:59 +02:00
|
|
|
mod document;
|
2019-11-13 11:50:15 +02:00
|
|
|
mod document_rels;
|
2019-11-06 07:55:14 +02:00
|
|
|
mod elements;
|
2019-11-14 12:21:45 +02:00
|
|
|
mod font_table;
|
2021-11-24 18:49:27 +02:00
|
|
|
mod footer;
|
|
|
|
mod footer_id;
|
2024-02-19 11:11:07 +02:00
|
|
|
mod footer_rels;
|
2024-06-24 14:37:27 +03:00
|
|
|
mod footnote_id;
|
|
|
|
mod footnotes;
|
2020-08-13 11:27:45 +03:00
|
|
|
mod header;
|
|
|
|
mod header_id;
|
2024-02-19 11:11:07 +02:00
|
|
|
mod header_rels;
|
2019-11-15 11:15:43 +02:00
|
|
|
mod history_id;
|
2022-07-06 04:47:15 +03:00
|
|
|
mod hyperlink_id;
|
2024-02-19 11:11:07 +02:00
|
|
|
mod image_collector;
|
2019-12-06 12:18:48 +02:00
|
|
|
mod numberings;
|
2020-08-13 19:57:59 +03:00
|
|
|
mod paragraph_id;
|
2022-01-07 18:28:34 +02:00
|
|
|
mod paragraph_property_change_id;
|
2020-05-14 06:01:20 +03:00
|
|
|
mod pic_id;
|
2022-01-02 19:18:04 +02:00
|
|
|
mod preset_styles;
|
2019-11-05 11:03:23 +02:00
|
|
|
mod rels;
|
2019-11-14 08:54:39 +02:00
|
|
|
mod settings;
|
2019-11-07 06:57:58 +02:00
|
|
|
mod styles;
|
2021-06-30 16:37:13 +03:00
|
|
|
mod taskpanes;
|
|
|
|
mod taskpanes_rels;
|
2022-01-27 10:23:30 +02:00
|
|
|
mod theme;
|
2022-01-02 19:18:04 +02:00
|
|
|
mod toc_key;
|
2021-04-09 05:30:50 +03:00
|
|
|
mod web_settings;
|
2021-06-30 16:37:13 +03:00
|
|
|
mod webextension;
|
2019-11-07 11:45:03 +02:00
|
|
|
mod xml_docx;
|
2019-11-05 08:10:48 +02:00
|
|
|
|
2019-11-15 11:15:43 +02:00
|
|
|
pub(crate) use build_xml::BuildXML;
|
|
|
|
pub(crate) use history_id::HistoryId;
|
2022-07-06 04:47:15 +03:00
|
|
|
pub(crate) use hyperlink_id::*;
|
2020-08-13 19:57:59 +03:00
|
|
|
pub(crate) use paragraph_id::*;
|
2022-01-07 18:28:34 +02:00
|
|
|
pub(crate) use paragraph_property_change_id::ParagraphPropertyChangeId;
|
2020-05-14 06:01:20 +03:00
|
|
|
pub(crate) use pic_id::*;
|
2019-11-06 07:55:14 +02:00
|
|
|
|
2022-01-02 19:18:04 +02:00
|
|
|
pub use bookmark_id::*;
|
2019-12-04 10:39:59 +02:00
|
|
|
pub use comments::*;
|
2020-08-13 19:57:59 +03:00
|
|
|
pub use comments_extended::*;
|
2019-11-07 09:08:59 +02:00
|
|
|
pub use content_types::*;
|
2021-07-13 12:46:15 +03:00
|
|
|
pub use custom_item::*;
|
|
|
|
pub use custom_item_property::*;
|
|
|
|
pub use custom_item_rels::*;
|
2019-11-07 09:08:59 +02:00
|
|
|
pub use doc_props::*;
|
|
|
|
pub use document::*;
|
2019-11-13 11:50:15 +02:00
|
|
|
pub use document_rels::*;
|
2019-11-07 09:08:59 +02:00
|
|
|
pub use elements::*;
|
2019-11-14 12:21:45 +02:00
|
|
|
pub use font_table::*;
|
2021-11-24 18:49:27 +02:00
|
|
|
pub use footer::*;
|
|
|
|
pub use footer_id::*;
|
2024-02-19 11:11:07 +02:00
|
|
|
pub use footer_rels::*;
|
2024-06-24 14:37:27 +03:00
|
|
|
pub use footnotes::*;
|
2020-08-13 11:27:45 +03:00
|
|
|
pub use header::*;
|
2021-11-25 16:33:13 +02:00
|
|
|
pub use header_id::*;
|
2024-02-19 11:11:07 +02:00
|
|
|
pub use header_rels::*;
|
2019-12-06 12:18:48 +02:00
|
|
|
pub use numberings::*;
|
2019-11-07 09:08:59 +02:00
|
|
|
pub use rels::*;
|
2019-11-14 08:54:39 +02:00
|
|
|
pub use settings::*;
|
2019-11-07 09:08:59 +02:00
|
|
|
pub use styles::*;
|
2021-06-30 16:37:13 +03:00
|
|
|
pub use taskpanes::*;
|
|
|
|
pub use taskpanes_rels::*;
|
2022-01-27 10:23:30 +02:00
|
|
|
pub use theme::*;
|
2022-01-02 19:18:04 +02:00
|
|
|
pub use toc_key::*;
|
2021-04-09 05:30:50 +03:00
|
|
|
pub use web_settings::*;
|
2021-06-30 16:37:13 +03:00
|
|
|
pub use webextension::*;
|
2019-11-07 11:45:03 +02:00
|
|
|
pub use xml_docx::*;
|
2019-11-05 08:10:48 +02:00
|
|
|
|
2022-03-28 13:40:32 +03:00
|
|
|
use serde::{ser, Serialize};
|
|
|
|
|
2024-02-19 11:11:07 +02:00
|
|
|
use self::image_collector::{collect_images_from_paragraph, collect_images_from_table};
|
|
|
|
|
2022-03-28 13:40:32 +03:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Image(pub Vec<u8>);
|
|
|
|
|
2022-06-14 12:11:52 +03:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Png(pub Vec<u8>);
|
|
|
|
|
2022-03-28 13:40:32 +03:00
|
|
|
pub type ImageIdAndPath = (String, String);
|
|
|
|
pub type ImageIdAndBuf = (String, Vec<u8>);
|
|
|
|
|
|
|
|
impl ser::Serialize for Image {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: ser::Serializer,
|
|
|
|
{
|
|
|
|
let base64 = base64::display::Base64Display::with_config(&*self.0, base64::STANDARD);
|
|
|
|
serializer.collect_str(&base64)
|
|
|
|
}
|
|
|
|
}
|
2020-02-11 10:01:39 +02:00
|
|
|
|
2022-06-14 12:11:52 +03:00
|
|
|
impl ser::Serialize for Png {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: ser::Serializer,
|
|
|
|
{
|
|
|
|
let base64 = base64::display::Base64Display::with_config(&*self.0, base64::STANDARD);
|
|
|
|
serializer.collect_str(&base64)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-13 12:46:15 +03:00
|
|
|
#[derive(Debug, Clone, Serialize)]
|
2020-02-11 10:01:39 +02:00
|
|
|
#[serde(rename_all = "camelCase")]
|
2019-12-08 21:14:27 +02:00
|
|
|
pub struct Docx {
|
2020-02-11 10:01:39 +02:00
|
|
|
pub content_type: ContentTypes,
|
|
|
|
pub rels: Rels,
|
|
|
|
pub document_rels: DocumentRels,
|
|
|
|
pub doc_props: DocProps,
|
2019-12-11 07:12:22 +02:00
|
|
|
pub styles: Styles,
|
|
|
|
pub document: Document,
|
|
|
|
pub comments: Comments,
|
|
|
|
pub numberings: Numberings,
|
|
|
|
pub settings: Settings,
|
|
|
|
pub font_table: FontTable,
|
2022-03-28 13:40:32 +03:00
|
|
|
pub media: Vec<(String, Vec<u8>)>,
|
2020-08-13 19:57:59 +03:00
|
|
|
pub comments_extended: CommentsExtended,
|
2021-04-09 05:30:50 +03:00
|
|
|
pub web_settings: WebSettings,
|
2021-06-30 16:37:13 +03:00
|
|
|
pub taskpanes: Option<Taskpanes>,
|
|
|
|
pub taskpanes_rels: TaskpanesRels,
|
|
|
|
pub web_extensions: Vec<WebExtension>,
|
2021-07-13 12:46:15 +03:00
|
|
|
pub custom_items: Vec<CustomItem>,
|
|
|
|
pub custom_item_props: Vec<CustomItemProperty>,
|
|
|
|
pub custom_item_rels: Vec<CustomItemRels>,
|
2022-01-27 10:23:30 +02:00
|
|
|
// reader only
|
|
|
|
pub themes: Vec<Theme>,
|
2022-03-28 13:40:32 +03:00
|
|
|
// reader only
|
2022-06-14 12:11:52 +03:00
|
|
|
pub images: Vec<(String, String, Image, Png)>,
|
2022-08-09 09:32:17 +03:00
|
|
|
// reader only
|
|
|
|
pub hyperlinks: Vec<(String, String, String)>,
|
2024-06-24 14:37:27 +03:00
|
|
|
pub footnotes: Footnotes,
|
2019-11-05 08:10:48 +02:00
|
|
|
}
|
|
|
|
|
2019-12-08 21:14:27 +02:00
|
|
|
impl Default for Docx {
|
2019-11-07 10:31:04 +02:00
|
|
|
fn default() -> Self {
|
2020-02-11 10:01:39 +02:00
|
|
|
let content_type = ContentTypes::new().set_default();
|
2020-02-11 15:06:54 +02:00
|
|
|
let rels = Rels::new().set_default();
|
2019-11-14 18:50:30 +02:00
|
|
|
let doc_props = DocProps::new(CorePropsConfig::new());
|
2019-11-07 10:31:04 +02:00
|
|
|
let styles = Styles::new();
|
|
|
|
let document = Document::new();
|
2019-11-13 11:50:15 +02:00
|
|
|
let document_rels = DocumentRels::new();
|
2019-11-14 08:54:39 +02:00
|
|
|
let settings = Settings::new();
|
2019-11-14 12:21:45 +02:00
|
|
|
let font_table = FontTable::new();
|
2019-12-04 10:39:59 +02:00
|
|
|
let comments = Comments::new();
|
2019-12-06 12:18:48 +02:00
|
|
|
let numberings = Numberings::new();
|
2020-05-14 06:01:20 +03:00
|
|
|
let media = vec![];
|
2020-08-13 19:57:59 +03:00
|
|
|
let comments_extended = CommentsExtended::new();
|
2021-04-09 05:30:50 +03:00
|
|
|
let web_settings = WebSettings::new();
|
2024-06-24 14:37:27 +03:00
|
|
|
let footnotes = Footnotes::default();
|
2020-08-13 19:57:59 +03:00
|
|
|
|
2019-11-07 09:08:59 +02:00
|
|
|
Docx {
|
2019-11-05 12:20:40 +02:00
|
|
|
content_type,
|
|
|
|
rels,
|
2021-06-23 12:39:01 +03:00
|
|
|
document_rels,
|
2019-11-05 12:20:40 +02:00
|
|
|
doc_props,
|
2019-11-07 10:31:04 +02:00
|
|
|
styles,
|
|
|
|
document,
|
2019-12-04 10:39:59 +02:00
|
|
|
comments,
|
2021-06-23 12:39:01 +03:00
|
|
|
numberings,
|
2019-11-14 08:54:39 +02:00
|
|
|
settings,
|
2019-11-14 12:21:45 +02:00
|
|
|
font_table,
|
2020-05-14 06:01:20 +03:00
|
|
|
media,
|
2020-08-13 19:57:59 +03:00
|
|
|
comments_extended,
|
2021-04-09 05:30:50 +03:00
|
|
|
web_settings,
|
2021-06-30 16:37:13 +03:00
|
|
|
taskpanes: None,
|
|
|
|
taskpanes_rels: TaskpanesRels::new(),
|
|
|
|
web_extensions: vec![],
|
2021-07-13 12:46:15 +03:00
|
|
|
custom_items: vec![],
|
|
|
|
custom_item_props: vec![],
|
|
|
|
custom_item_rels: vec![],
|
2022-01-27 10:23:30 +02:00
|
|
|
themes: vec![],
|
2022-03-28 13:40:32 +03:00
|
|
|
images: vec![],
|
2022-08-09 09:32:17 +03:00
|
|
|
hyperlinks: vec![],
|
2024-06-24 14:37:27 +03:00
|
|
|
footnotes,
|
2019-11-07 10:31:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-08 21:14:27 +02:00
|
|
|
impl Docx {
|
|
|
|
pub fn new() -> Docx {
|
2019-11-07 10:31:04 +02:00
|
|
|
Default::default()
|
|
|
|
}
|
|
|
|
|
2020-02-11 10:01:39 +02:00
|
|
|
pub fn document(mut self, d: Document) -> Docx {
|
2020-02-12 09:03:11 +02:00
|
|
|
for child in &self.document.children {
|
|
|
|
match child {
|
|
|
|
DocumentChild::Paragraph(paragraph) => {
|
|
|
|
if paragraph.has_numbering {
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DocumentChild::Table(table) => {
|
|
|
|
if table.has_numbering {
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
|
|
|
}
|
2020-09-02 12:23:53 +03:00
|
|
|
_ => {}
|
2020-02-12 09:03:11 +02:00
|
|
|
}
|
|
|
|
}
|
2020-02-11 10:01:39 +02:00
|
|
|
self.document = d;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-02-12 09:03:11 +02:00
|
|
|
pub fn styles(mut self, s: Styles) -> Self {
|
|
|
|
self.styles = s;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-12-05 17:28:31 +02:00
|
|
|
pub fn add_style(mut self, s: Style) -> Self {
|
|
|
|
self.styles = self.styles.add_style(s);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-02-12 12:19:38 +02:00
|
|
|
pub fn numberings(mut self, n: Numberings) -> Self {
|
|
|
|
self.numberings = n;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-09-07 09:46:23 +03:00
|
|
|
pub fn settings(mut self, s: Settings) -> Self {
|
|
|
|
self.settings = s;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-04-09 05:30:50 +03:00
|
|
|
// reader only
|
|
|
|
pub(crate) fn web_settings(mut self, s: WebSettings) -> Self {
|
|
|
|
self.web_settings = s;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-03-28 13:40:32 +03:00
|
|
|
// reader only
|
2022-05-20 11:00:24 +03:00
|
|
|
pub(crate) fn add_image(
|
|
|
|
mut self,
|
|
|
|
id: impl Into<String>,
|
|
|
|
path: impl Into<String>,
|
|
|
|
buf: Vec<u8>,
|
|
|
|
) -> Self {
|
2024-10-22 04:28:58 +03:00
|
|
|
#[cfg(feature = "image")]
|
2022-07-22 05:46:07 +03:00
|
|
|
if let Ok(dimg) = image::load_from_memory(&buf) {
|
|
|
|
let mut png = std::io::Cursor::new(vec![]);
|
|
|
|
// For now only png supported
|
2024-10-22 04:28:58 +03:00
|
|
|
dimg.write_to(&mut png, image::ImageFormat::Png)
|
2022-07-22 05:46:07 +03:00
|
|
|
.expect("Unable to write dynamic image");
|
|
|
|
|
|
|
|
self.images
|
|
|
|
.push((id.into(), path.into(), Image(buf), Png(png.into_inner())));
|
|
|
|
}
|
2024-10-22 04:28:58 +03:00
|
|
|
#[cfg(not(feature = "image"))]
|
|
|
|
// without 'image' crate we can only test for PNG file signature
|
|
|
|
if buf.starts_with(&[137, 80, 78, 71, 13, 10, 26, 10]) {
|
|
|
|
self.images
|
|
|
|
.push((id.into(), path.into(), Image(buf.clone()), Png(buf)));
|
|
|
|
}
|
2022-03-28 13:40:32 +03:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-08-09 09:32:17 +03:00
|
|
|
// reader only
|
|
|
|
pub(crate) fn add_hyperlink(
|
|
|
|
mut self,
|
|
|
|
id: impl Into<String>,
|
|
|
|
path: impl Into<String>,
|
|
|
|
r#type: impl Into<String>,
|
|
|
|
) -> Self {
|
|
|
|
self.hyperlinks
|
|
|
|
.push((id.into(), path.into(), r#type.into()));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-12-15 15:33:01 +02:00
|
|
|
pub fn comments(mut self, c: Comments) -> Self {
|
|
|
|
self.comments = c;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn comments_extended(mut self, c: CommentsExtended) -> Self {
|
|
|
|
self.comments_extended = c;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-08 21:14:27 +02:00
|
|
|
pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
|
2019-12-16 04:36:04 +02:00
|
|
|
if p.has_numbering {
|
|
|
|
// If this document has numbering, set numberings.xml to document_rels.
|
|
|
|
// This is because numberings.xml without numbering cause an error on word online.
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
2019-11-07 10:31:04 +02:00
|
|
|
self.document = self.document.add_paragraph(p);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-12-02 17:56:29 +02:00
|
|
|
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Docx {
|
|
|
|
if t.has_numbering {
|
|
|
|
// If this document has numbering, set numberings.xml to document_rels.
|
|
|
|
// This is because numberings.xml without numbering cause an error on word online.
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
|
|
|
self.document = self.document.add_structured_data_tag(t);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-12-05 17:28:31 +02:00
|
|
|
pub fn add_table_of_contents(mut self, t: TableOfContents) -> Docx {
|
|
|
|
self.document = self.document.add_table_of_contents(t);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-09-02 12:23:53 +03:00
|
|
|
pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Docx {
|
|
|
|
self.document = self.document.add_bookmark_start(id, name);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_bookmark_end(mut self, id: usize) -> Docx {
|
|
|
|
self.document = self.document.add_bookmark_end(id);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-08 21:14:27 +02:00
|
|
|
pub fn add_table(mut self, t: Table) -> Docx {
|
2019-12-16 04:36:04 +02:00
|
|
|
if t.has_numbering {
|
|
|
|
// If this document has numbering, set numberings.xml to document_rels.
|
|
|
|
// This is because numberings.xml without numbering cause an error on word online.
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
2019-11-13 06:55:58 +02:00
|
|
|
self.document = self.document.add_table(t);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-11-25 16:33:13 +02:00
|
|
|
pub fn header(mut self, header: Header) -> Self {
|
|
|
|
if header.has_numbering {
|
2021-11-24 18:49:27 +02:00
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
2021-11-27 12:12:06 +02:00
|
|
|
let count = self.document_rels.header_count + 1;
|
|
|
|
self.document.section_property = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.header(header, &create_header_rid(count));
|
|
|
|
self.document_rels.header_count = count;
|
|
|
|
self.content_type = self.content_type.add_header();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn first_header(mut self, header: Header) -> Self {
|
|
|
|
if header.has_numbering {
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
|
|
|
let count = self.document_rels.header_count + 1;
|
|
|
|
self.document.section_property = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.first_header(header, &create_header_rid(count));
|
|
|
|
self.document_rels.header_count = count;
|
|
|
|
self.content_type = self.content_type.add_header();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn even_header(mut self, header: Header) -> Self {
|
|
|
|
if header.has_numbering {
|
|
|
|
self.document_rels.has_numberings = true;
|
2021-11-24 18:49:27 +02:00
|
|
|
}
|
2021-11-27 12:12:06 +02:00
|
|
|
let count = self.document_rels.header_count + 1;
|
|
|
|
self.document.section_property = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.even_header(header, &create_header_rid(count));
|
|
|
|
self.document_rels.header_count = count;
|
|
|
|
self.content_type = self.content_type.add_header();
|
|
|
|
self.settings = self.settings.even_and_odd_headers();
|
2021-11-24 18:49:27 +02:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-11-27 12:12:06 +02:00
|
|
|
pub fn footer(mut self, footer: Footer) -> Self {
|
2021-11-25 16:33:13 +02:00
|
|
|
if footer.has_numbering {
|
2021-11-24 18:49:27 +02:00
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
2021-11-27 12:12:06 +02:00
|
|
|
let count = self.document_rels.footer_count + 1;
|
|
|
|
self.document.section_property = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.footer(footer, &create_footer_rid(count));
|
|
|
|
self.document_rels.footer_count = count;
|
|
|
|
self.content_type = self.content_type.add_footer();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn first_footer(mut self, footer: Footer) -> Self {
|
|
|
|
if footer.has_numbering {
|
|
|
|
self.document_rels.has_numberings = true;
|
2021-11-24 18:49:27 +02:00
|
|
|
}
|
2021-11-27 12:12:06 +02:00
|
|
|
let count = self.document_rels.footer_count + 1;
|
|
|
|
self.document.section_property = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.first_footer(footer, &create_footer_rid(count));
|
|
|
|
self.document_rels.footer_count = count;
|
|
|
|
self.content_type = self.content_type.add_footer();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn even_footer(mut self, footer: Footer) -> Self {
|
|
|
|
if footer.has_numbering {
|
|
|
|
self.document_rels.has_numberings = true;
|
|
|
|
}
|
|
|
|
let count = self.document_rels.footer_count + 1;
|
|
|
|
self.document.section_property = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.even_footer(footer, &create_footer_rid(count));
|
|
|
|
self.document_rels.footer_count = count;
|
|
|
|
self.content_type = self.content_type.add_footer();
|
|
|
|
self.settings = self.settings.even_and_odd_headers();
|
2021-11-24 18:49:27 +02:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-02-11 17:21:26 +02:00
|
|
|
pub fn add_abstract_numbering(mut self, num: AbstractNumbering) -> Docx {
|
|
|
|
self.numberings = self.numberings.add_abstract_numbering(num);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-08 21:14:27 +02:00
|
|
|
pub fn add_numbering(mut self, num: Numbering) -> Docx {
|
2019-12-06 12:18:48 +02:00
|
|
|
self.numberings = self.numberings.add_numbering(num);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-14 17:39:15 +02:00
|
|
|
pub fn created_at(mut self, date: &str) -> Self {
|
|
|
|
self.doc_props = self.doc_props.created_at(date);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn updated_at(mut self, date: &str) -> Self {
|
|
|
|
self.doc_props = self.doc_props.updated_at(date);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-06-23 12:39:01 +03:00
|
|
|
pub fn custom_property(mut self, name: impl Into<String>, item: impl Into<String>) -> Self {
|
|
|
|
self.doc_props = self.doc_props.custom_property(name, item);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-08-19 18:53:35 +03:00
|
|
|
pub fn doc_id(mut self, id: &str) -> Self {
|
|
|
|
self.settings = self.settings.doc_id(id);
|
|
|
|
self
|
2021-03-26 06:37:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_tab_stop(mut self, stop: usize) -> Self {
|
|
|
|
self.settings = self.settings.default_tab_stop(stop);
|
|
|
|
self
|
2020-08-19 18:53:35 +03:00
|
|
|
}
|
|
|
|
|
2020-12-15 08:38:17 +02:00
|
|
|
pub fn add_doc_var(mut self, name: &str, val: &str) -> Self {
|
|
|
|
self.settings = self.settings.add_doc_var(name, val);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-10-09 14:30:55 +03:00
|
|
|
pub fn page_size(mut self, w: u32, h: u32) -> Self {
|
|
|
|
self.document = self.document.page_size(PageSize::new().size(w, h));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn page_margin(mut self, margin: crate::types::PageMargin) -> Self {
|
|
|
|
self.document = self.document.page_margin(margin);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-03-24 09:51:11 +02:00
|
|
|
pub fn page_orient(mut self, o: crate::types::PageOrientationType) -> Self {
|
|
|
|
self.document = self.document.page_orient(o);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-12-14 08:01:23 +02:00
|
|
|
pub fn default_size(mut self, size: usize) -> Self {
|
|
|
|
self.styles = self.styles.default_size(size);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_spacing(mut self, spacing: i32) -> Self {
|
|
|
|
self.styles = self.styles.default_spacing(spacing);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn default_fonts(mut self, font: RunFonts) -> Self {
|
|
|
|
self.styles = self.styles.default_fonts(font);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2024-01-17 15:40:47 +02:00
|
|
|
pub fn default_line_spacing(mut self, spacing: LineSpacing) -> Self {
|
|
|
|
self.styles = self.styles.default_line_spacing(spacing);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-06-30 16:37:13 +03:00
|
|
|
pub fn taskpanes(mut self) -> Self {
|
|
|
|
self.taskpanes = Some(Taskpanes::new());
|
|
|
|
self.rels = self.rels.add_taskpanes_rel();
|
|
|
|
self.content_type = self.content_type.add_taskpanes();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn web_extension(mut self, ext: WebExtension) -> Self {
|
|
|
|
self.web_extensions.push(ext);
|
|
|
|
self.taskpanes_rels = self.taskpanes_rels.add_rel();
|
|
|
|
self.content_type = self.content_type.add_web_extensions();
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2021-07-13 12:46:15 +03:00
|
|
|
pub fn add_custom_item(mut self, id: &str, xml: &str) -> Self {
|
|
|
|
let x = CustomItem::from_str(xml).expect("should parse xml string");
|
|
|
|
self.content_type = self.content_type.add_custom_xml();
|
|
|
|
let rel = CustomItemRels::new().add_item();
|
|
|
|
self.custom_item_props.push(CustomItemProperty::new(id));
|
|
|
|
self.document_rels = self.document_rels.add_custom_item();
|
|
|
|
self.custom_item_rels.push(rel);
|
|
|
|
self.custom_items.push(x);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2024-03-06 12:13:11 +02:00
|
|
|
pub fn page_num_type(mut self, p: PageNumType) -> Self {
|
|
|
|
self.document = self.document.page_num_type(p);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-01-02 19:18:04 +02:00
|
|
|
pub fn build(mut self) -> XMLDocx {
|
2020-12-21 13:52:15 +02:00
|
|
|
self.reset();
|
|
|
|
|
2022-07-06 04:47:15 +03:00
|
|
|
self.update_dependencies();
|
2021-06-30 16:37:13 +03:00
|
|
|
|
2022-03-28 13:40:32 +03:00
|
|
|
let tocs: Vec<(usize, Box<TableOfContents>)> = self
|
2022-01-02 19:18:04 +02:00
|
|
|
.document
|
|
|
|
.children
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.filter_map(|(i, child)| {
|
|
|
|
if let DocumentChild::TableOfContents(toc) = child {
|
|
|
|
Some((i, toc.clone()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
if !tocs.is_empty() {
|
|
|
|
for i in 1..=9 {
|
|
|
|
self.styles = self
|
|
|
|
.styles
|
|
|
|
.add_style(crate::documents::preset_styles::toc(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i, toc) in tocs {
|
2022-01-06 09:13:45 +02:00
|
|
|
if toc.items.is_empty() && toc.auto {
|
2022-03-28 13:40:32 +03:00
|
|
|
let children =
|
|
|
|
update_document_by_toc(self.document.children, &self.styles, *toc, i);
|
2022-01-02 19:18:04 +02:00
|
|
|
self.document.children = children;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-19 11:11:07 +02:00
|
|
|
let (images, mut images_bufs) = self.images_in_doc();
|
|
|
|
let (header_images, header_images_bufs) = self.images_in_header();
|
|
|
|
let (footer_images, footer_images_bufs) = self.images_in_footer();
|
|
|
|
|
|
|
|
images_bufs.extend(header_images_bufs);
|
|
|
|
images_bufs.extend(footer_images_bufs);
|
|
|
|
|
|
|
|
let mut header_rels = vec![HeaderRels::new(); 3];
|
|
|
|
for (i, images) in header_images.iter().enumerate() {
|
|
|
|
if let Some(h) = header_rels.get_mut(i) {
|
|
|
|
h.set_images(images.to_owned());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut footer_rels = vec![FooterRels::new(); 3];
|
|
|
|
for (i, images) in footer_images.iter().enumerate() {
|
|
|
|
if let Some(f) = footer_rels.get_mut(i) {
|
|
|
|
f.set_images(images.to_owned());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-30 16:37:13 +03:00
|
|
|
let web_extensions = self.web_extensions.iter().map(|ext| ext.build()).collect();
|
2021-07-13 12:46:15 +03:00
|
|
|
let custom_items = self.custom_items.iter().map(|xml| xml.build()).collect();
|
|
|
|
let custom_item_props = self.custom_item_props.iter().map(|p| p.build()).collect();
|
|
|
|
let custom_item_rels = self
|
|
|
|
.custom_item_rels
|
|
|
|
.iter()
|
|
|
|
.map(|rel| rel.build())
|
|
|
|
.collect();
|
2021-06-30 16:37:13 +03:00
|
|
|
|
2022-03-28 13:40:32 +03:00
|
|
|
self.document_rels.images = images;
|
2020-05-14 06:01:20 +03:00
|
|
|
|
2021-11-27 12:12:06 +02:00
|
|
|
let headers: Vec<Vec<u8>> = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.get_headers()
|
|
|
|
.iter()
|
|
|
|
.map(|h| h.build())
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let footers: Vec<Vec<u8>> = self
|
|
|
|
.document
|
|
|
|
.section_property
|
|
|
|
.get_footers()
|
|
|
|
.iter()
|
|
|
|
.map(|h| h.build())
|
|
|
|
.collect();
|
2021-11-24 18:49:27 +02:00
|
|
|
|
2024-06-24 14:37:27 +03:00
|
|
|
// Collect footnotes
|
|
|
|
if self.collect_footnotes() {
|
|
|
|
// Relationship entry for footnotes
|
|
|
|
self.content_type = self.content_type.add_footnotes();
|
|
|
|
self.document_rels.has_footnotes = true;
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:31:04 +02:00
|
|
|
XMLDocx {
|
|
|
|
content_type: self.content_type.build(),
|
|
|
|
rels: self.rels.build(),
|
|
|
|
doc_props: self.doc_props.build(),
|
|
|
|
styles: self.styles.build(),
|
|
|
|
document: self.document.build(),
|
2019-12-05 08:44:18 +02:00
|
|
|
comments: self.comments.build(),
|
2019-11-13 11:50:15 +02:00
|
|
|
document_rels: self.document_rels.build(),
|
2024-02-19 11:11:07 +02:00
|
|
|
header_rels: header_rels.into_iter().map(|r| r.build()).collect(),
|
|
|
|
footer_rels: footer_rels.into_iter().map(|r| r.build()).collect(),
|
2019-11-14 08:54:39 +02:00
|
|
|
settings: self.settings.build(),
|
2019-11-14 12:21:45 +02:00
|
|
|
font_table: self.font_table.build(),
|
2019-12-06 12:18:48 +02:00
|
|
|
numberings: self.numberings.build(),
|
2022-03-28 13:40:32 +03:00
|
|
|
media: images_bufs,
|
2021-11-27 12:12:06 +02:00
|
|
|
headers,
|
|
|
|
footers,
|
2020-08-13 19:57:59 +03:00
|
|
|
comments_extended: self.comments_extended.build(),
|
2021-06-30 16:37:13 +03:00
|
|
|
taskpanes: self.taskpanes.map(|taskpanes| taskpanes.build()),
|
|
|
|
taskpanes_rels: self.taskpanes_rels.build(),
|
|
|
|
web_extensions,
|
2021-07-13 12:46:15 +03:00
|
|
|
custom_items,
|
|
|
|
custom_item_rels,
|
|
|
|
custom_item_props,
|
2024-06-24 14:37:27 +03:00
|
|
|
footnotes: self.footnotes.build(),
|
2019-11-05 12:20:40 +02:00
|
|
|
}
|
2019-11-05 08:10:48 +02:00
|
|
|
}
|
2019-12-05 08:44:18 +02:00
|
|
|
|
2020-12-21 11:44:31 +02:00
|
|
|
pub fn json(&self) -> String {
|
2020-12-21 13:52:15 +02:00
|
|
|
self.reset();
|
|
|
|
|
2020-02-12 12:19:38 +02:00
|
|
|
serde_json::to_string_pretty(&self).unwrap()
|
2020-02-11 10:01:39 +02:00
|
|
|
}
|
|
|
|
|
2020-12-21 13:52:15 +02:00
|
|
|
// Internal: for docx-wasm
|
|
|
|
pub fn json_with_update_comments(&mut self) -> String {
|
|
|
|
self.reset();
|
|
|
|
|
2022-07-06 04:47:15 +03:00
|
|
|
self.update_dependencies();
|
2020-12-21 13:52:15 +02:00
|
|
|
serde_json::to_string_pretty(&self).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reset(&self) {
|
|
|
|
crate::reset_para_id();
|
|
|
|
}
|
|
|
|
|
2021-12-17 18:03:02 +02:00
|
|
|
fn insert_comment_to_map(
|
|
|
|
&self,
|
|
|
|
comment_map: &mut HashMap<usize, String>,
|
|
|
|
c: &CommentRangeStart,
|
|
|
|
) {
|
|
|
|
let comment = c.get_comment();
|
|
|
|
let comment_id = comment.id();
|
|
|
|
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());
|
|
|
|
}
|
2022-06-14 12:36:54 +03:00
|
|
|
// TODO: Support table in comment
|
2021-12-17 18:03:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-05 09:00:32 +02:00
|
|
|
// Traverse and clone comments from document and add to comments node.
|
2022-07-06 04:47:15 +03:00
|
|
|
fn update_dependencies(&mut self) {
|
2019-12-08 21:14:27 +02:00
|
|
|
let mut comments: Vec<Comment> = vec![];
|
2020-08-13 19:57:59 +03:00
|
|
|
let mut comments_extended: Vec<CommentExtended> = vec![];
|
|
|
|
let mut comment_map: HashMap<usize, String> = HashMap::new();
|
2022-07-06 04:47:15 +03:00
|
|
|
|
|
|
|
let mut hyperlink_map: HashMap<String, String> = HashMap::new();
|
|
|
|
|
2019-12-05 08:44:18 +02:00
|
|
|
for child in &self.document.children {
|
|
|
|
match child {
|
2019-12-05 09:00:32 +02:00
|
|
|
DocumentChild::Paragraph(paragraph) => {
|
|
|
|
for child in ¶graph.children {
|
2020-01-24 10:57:14 +02:00
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
2021-12-17 18:03:02 +02:00
|
|
|
self.insert_comment_to_map(&mut comment_map, c);
|
|
|
|
}
|
|
|
|
if let ParagraphChild::Hyperlink(h) = child {
|
2022-07-06 04:47:15 +03:00
|
|
|
if let HyperlinkData::External { rid, path } = h.link.clone() {
|
|
|
|
hyperlink_map.insert(rid, path);
|
|
|
|
};
|
2021-12-17 18:03:02 +02:00
|
|
|
for child in &h.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
self.insert_comment_to_map(&mut comment_map, c);
|
2020-12-21 10:30:42 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-13 19:57:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DocumentChild::Table(table) => {
|
2022-07-06 04:47:15 +03:00
|
|
|
collect_dependencies_in_table(
|
2022-06-14 12:36:54 +03:00
|
|
|
table,
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&mut comment_map,
|
2022-07-06 04:47:15 +03:00
|
|
|
&mut hyperlink_map,
|
2022-06-14 12:36:54 +03:00
|
|
|
);
|
2020-08-13 19:57:59 +03:00
|
|
|
}
|
2020-09-02 12:23:53 +03:00
|
|
|
_ => {}
|
2020-08-13 19:57:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for child in &self.document.children {
|
|
|
|
match child {
|
|
|
|
DocumentChild::Paragraph(paragraph) => {
|
|
|
|
for child in ¶graph.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
2022-06-14 12:36:54 +03:00
|
|
|
push_comment_and_comment_extended(
|
2021-12-17 18:03:02 +02:00
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&comment_map,
|
|
|
|
c,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let ParagraphChild::Hyperlink(h) = child {
|
2022-07-06 04:47:15 +03:00
|
|
|
if let HyperlinkData::External { rid, path } = h.link.clone() {
|
|
|
|
hyperlink_map.insert(rid, path);
|
|
|
|
};
|
2021-12-17 18:03:02 +02:00
|
|
|
for child in &h.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
2022-06-14 12:36:54 +03:00
|
|
|
push_comment_and_comment_extended(
|
2021-12-17 18:03:02 +02:00
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&comment_map,
|
|
|
|
c,
|
|
|
|
);
|
2020-12-21 10:30:42 +02:00
|
|
|
}
|
2020-08-13 19:57:59 +03:00
|
|
|
}
|
2019-12-05 08:44:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-05 09:00:32 +02:00
|
|
|
DocumentChild::Table(table) => {
|
2022-07-06 04:47:15 +03:00
|
|
|
collect_dependencies_in_table(
|
2022-06-14 12:36:54 +03:00
|
|
|
table,
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&mut comment_map,
|
2022-07-06 04:47:15 +03:00
|
|
|
&mut hyperlink_map,
|
2022-06-14 12:36:54 +03:00
|
|
|
);
|
2019-12-05 09:00:32 +02:00
|
|
|
}
|
2023-03-16 11:48:24 +02:00
|
|
|
DocumentChild::TableOfContents(toc) => {
|
|
|
|
// TODO:refine later
|
|
|
|
for child in &toc.before_contents {
|
|
|
|
if let TocContent::Paragraph(paragraph) = child {
|
|
|
|
for child in ¶graph.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
push_comment_and_comment_extended(
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&comment_map,
|
|
|
|
c,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let ParagraphChild::Hyperlink(h) = child {
|
|
|
|
if let HyperlinkData::External { rid, path } = h.link.clone() {
|
|
|
|
hyperlink_map.insert(rid, path);
|
|
|
|
};
|
|
|
|
for child in &h.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
push_comment_and_comment_extended(
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&comment_map,
|
|
|
|
c,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let TocContent::Table(table) = child {
|
|
|
|
collect_dependencies_in_table(
|
|
|
|
table,
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&mut comment_map,
|
|
|
|
&mut hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for child in &toc.after_contents {
|
|
|
|
if let TocContent::Paragraph(paragraph) = child {
|
|
|
|
for child in ¶graph.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
push_comment_and_comment_extended(
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&comment_map,
|
|
|
|
c,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let ParagraphChild::Hyperlink(h) = child {
|
|
|
|
if let HyperlinkData::External { rid, path } = h.link.clone() {
|
|
|
|
hyperlink_map.insert(rid, path);
|
|
|
|
};
|
|
|
|
for child in &h.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
push_comment_and_comment_extended(
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&comment_map,
|
|
|
|
c,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let TocContent::Table(table) = child {
|
|
|
|
collect_dependencies_in_table(
|
|
|
|
table,
|
|
|
|
&mut comments,
|
|
|
|
&mut comments_extended,
|
|
|
|
&mut comment_map,
|
|
|
|
&mut hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-02 12:23:53 +03:00
|
|
|
_ => {}
|
2019-12-05 08:44:18 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-15 19:19:30 +02:00
|
|
|
// If this document has comments, set comments.xml to document_rels.
|
|
|
|
// This is because comments.xml without comment cause an error on word online.
|
2020-01-24 10:57:14 +02:00
|
|
|
if !comments.is_empty() {
|
2019-12-15 19:19:30 +02:00
|
|
|
self.document_rels.has_comments = true;
|
|
|
|
}
|
2020-08-13 19:57:59 +03:00
|
|
|
|
|
|
|
self.comments_extended
|
|
|
|
.add_comments_extended(comments_extended);
|
|
|
|
|
2019-12-05 08:44:18 +02:00
|
|
|
self.comments.add_comments(comments);
|
2022-07-06 04:47:15 +03:00
|
|
|
|
|
|
|
for (id, d) in hyperlink_map {
|
2022-08-09 09:32:17 +03:00
|
|
|
self.document_rels
|
|
|
|
.hyperlinks
|
|
|
|
.push((id, d, "External".to_string())); // Now support external only
|
2022-07-06 04:47:15 +03:00
|
|
|
}
|
2019-12-05 08:44:18 +02:00
|
|
|
}
|
2020-05-14 06:01:20 +03:00
|
|
|
|
2020-12-15 15:33:01 +02:00
|
|
|
// Traverse and clone comments from document and add to comments node.
|
2022-06-14 12:36:54 +03:00
|
|
|
// reader only
|
2020-12-15 15:33:01 +02:00
|
|
|
pub(crate) fn store_comments(&mut self, comments: &[Comment]) {
|
|
|
|
for child in &mut self.document.children {
|
|
|
|
match child {
|
|
|
|
DocumentChild::Paragraph(paragraph) => {
|
|
|
|
for child in &mut paragraph.children {
|
|
|
|
if let ParagraphChild::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);
|
|
|
|
}
|
|
|
|
}
|
2021-01-06 13:31:53 +02:00
|
|
|
if let ParagraphChild::Insert(ref mut insert) = child {
|
|
|
|
for child in &mut insert.children {
|
|
|
|
if let InsertChild::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);
|
|
|
|
}
|
2024-09-06 08:44:31 +03:00
|
|
|
} else if let InsertChild::Delete(ref mut d) = child {
|
|
|
|
for child in &mut d.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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-06 13:31:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-27 12:44:29 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-15 15:33:01 +02:00
|
|
|
}
|
|
|
|
}
|
2022-06-14 12:36:54 +03:00
|
|
|
DocumentChild::Table(table) => store_comments_in_table(table, comments),
|
2020-12-15 15:33:01 +02:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !comments.is_empty() {
|
|
|
|
self.document_rels.has_comments = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 06:01:20 +03:00
|
|
|
// Traverse and collect images from document.
|
2024-02-19 11:11:07 +02:00
|
|
|
fn images_in_doc(&mut self) -> (Vec<ImageIdAndPath>, Vec<ImageIdAndBuf>) {
|
2022-03-28 13:40:32 +03:00
|
|
|
let mut images: Vec<(String, String)> = vec![];
|
|
|
|
let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
|
2020-05-14 06:01:20 +03:00
|
|
|
|
|
|
|
for child in &mut self.document.children {
|
|
|
|
match child {
|
|
|
|
DocumentChild::Paragraph(paragraph) => {
|
2024-02-19 11:11:07 +02:00
|
|
|
collect_images_from_paragraph(paragraph, &mut images, &mut image_bufs, None);
|
2020-05-14 06:01:20 +03:00
|
|
|
}
|
|
|
|
DocumentChild::Table(table) => {
|
2024-02-19 11:11:07 +02:00
|
|
|
collect_images_from_table(table, &mut images, &mut image_bufs, None);
|
2020-05-14 06:01:20 +03:00
|
|
|
}
|
2020-09-02 12:23:53 +03:00
|
|
|
_ => {}
|
2020-05-14 06:01:20 +03:00
|
|
|
}
|
|
|
|
}
|
2022-03-28 13:40:32 +03:00
|
|
|
(images, image_bufs)
|
2020-05-14 06:01:20 +03:00
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
|
|
|
|
fn images_in_header(&mut self) -> (Vec<Vec<ImageIdAndPath>>, Vec<ImageIdAndBuf>) {
|
|
|
|
let mut header_images: Vec<Vec<ImageIdAndPath>> = vec![vec![]; 3];
|
|
|
|
let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
|
|
|
|
|
|
|
|
if let Some(header) = &mut self.document.section_property.header.as_mut() {
|
|
|
|
let mut images: Vec<ImageIdAndPath> = vec![];
|
|
|
|
for child in header.children.iter_mut() {
|
|
|
|
match child {
|
|
|
|
HeaderChild::Paragraph(paragraph) => {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
HeaderChild::Table(table) => {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
2024-03-05 04:14:49 +02:00
|
|
|
HeaderChild::StructuredDataTag(tag) => {
|
|
|
|
for child in tag.children.iter_mut() {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
header_images[0] = images;
|
|
|
|
}
|
|
|
|
|
2024-03-29 09:03:13 +02:00
|
|
|
if let Some(header) = &mut self.document.section_property.first_header.as_mut() {
|
2024-02-19 11:11:07 +02:00
|
|
|
let mut images: Vec<ImageIdAndPath> = vec![];
|
|
|
|
for child in header.children.iter_mut() {
|
|
|
|
match child {
|
|
|
|
HeaderChild::Paragraph(paragraph) => {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
HeaderChild::Table(table) => {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
2024-03-05 04:14:49 +02:00
|
|
|
HeaderChild::StructuredDataTag(tag) => {
|
|
|
|
for child in tag.children.iter_mut() {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
header_images[1] = images;
|
|
|
|
}
|
|
|
|
|
2024-03-29 09:03:13 +02:00
|
|
|
if let Some(header) = &mut self.document.section_property.even_header.as_mut() {
|
2024-02-19 11:11:07 +02:00
|
|
|
let mut images: Vec<ImageIdAndPath> = vec![];
|
|
|
|
for child in header.children.iter_mut() {
|
|
|
|
match child {
|
|
|
|
HeaderChild::Paragraph(paragraph) => {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
HeaderChild::Table(table) => {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
2024-03-05 04:14:49 +02:00
|
|
|
HeaderChild::StructuredDataTag(tag) => {
|
|
|
|
for child in tag.children.iter_mut() {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
header_images[2] = images;
|
|
|
|
}
|
|
|
|
(header_images, image_bufs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Traverse and collect images from header.
|
|
|
|
fn images_in_footer(&mut self) -> (Vec<Vec<ImageIdAndPath>>, Vec<ImageIdAndBuf>) {
|
|
|
|
let mut footer_images: Vec<Vec<ImageIdAndPath>> = vec![vec![]; 3];
|
|
|
|
let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
|
|
|
|
|
|
|
|
if let Some(footer) = &mut self.document.section_property.footer.as_mut() {
|
|
|
|
let mut images: Vec<ImageIdAndPath> = vec![];
|
|
|
|
for child in footer.children.iter_mut() {
|
|
|
|
match child {
|
|
|
|
FooterChild::Paragraph(paragraph) => {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("footer"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
FooterChild::Table(table) => {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("footer"),
|
|
|
|
);
|
|
|
|
}
|
2024-03-05 04:14:49 +02:00
|
|
|
FooterChild::StructuredDataTag(tag) => {
|
|
|
|
for child in tag.children.iter_mut() {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
footer_images[0] = images;
|
|
|
|
}
|
|
|
|
|
2024-03-29 09:03:13 +02:00
|
|
|
if let Some(footer) = &mut self.document.section_property.first_footer.as_mut() {
|
2024-02-19 11:11:07 +02:00
|
|
|
let mut images: Vec<ImageIdAndPath> = vec![];
|
|
|
|
for child in footer.children.iter_mut() {
|
|
|
|
match child {
|
|
|
|
FooterChild::Paragraph(paragraph) => {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("footer"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
FooterChild::Table(table) => {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("footer"),
|
|
|
|
);
|
|
|
|
}
|
2024-03-05 04:14:49 +02:00
|
|
|
FooterChild::StructuredDataTag(tag) => {
|
|
|
|
for child in tag.children.iter_mut() {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
footer_images[1] = images;
|
|
|
|
}
|
|
|
|
|
2024-03-29 09:03:13 +02:00
|
|
|
if let Some(footer) = &mut self.document.section_property.even_footer.as_mut() {
|
2024-02-19 11:11:07 +02:00
|
|
|
let mut images: Vec<ImageIdAndPath> = vec![];
|
|
|
|
for child in footer.children.iter_mut() {
|
|
|
|
match child {
|
|
|
|
FooterChild::Paragraph(paragraph) => {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("footer"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
FooterChild::Table(table) => {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("footer"),
|
|
|
|
);
|
|
|
|
}
|
2024-03-05 04:14:49 +02:00
|
|
|
FooterChild::StructuredDataTag(tag) => {
|
|
|
|
for child in tag.children.iter_mut() {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_images_from_paragraph(
|
|
|
|
paragraph,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_images_from_table(
|
|
|
|
table,
|
|
|
|
&mut images,
|
|
|
|
&mut image_bufs,
|
|
|
|
Some("header"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-19 11:11:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
footer_images[2] = images;
|
|
|
|
}
|
|
|
|
(footer_images, image_bufs)
|
|
|
|
}
|
2024-06-24 14:37:27 +03:00
|
|
|
|
|
|
|
/// Collect footnotes from all Runs to the docx footnotes node.
|
|
|
|
pub fn collect_footnotes(&mut self) -> bool {
|
|
|
|
let footnotes: Vec<Footnote> = self
|
|
|
|
.document
|
|
|
|
.children
|
|
|
|
.iter()
|
|
|
|
.filter_map(|child| match child {
|
|
|
|
DocumentChild::Paragraph(paragraph) => Some(¶graph.children),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.flat_map(|children| children.iter())
|
|
|
|
.filter_map(|para_child| match para_child {
|
|
|
|
ParagraphChild::Run(run) => Some(&run.children),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.flat_map(|children| children.iter())
|
|
|
|
.filter_map(|run_child| match run_child {
|
|
|
|
RunChild::FootnoteReference(footnote_ref) => Some(footnote_ref),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
.map(Into::<Footnote>::into)
|
|
|
|
.collect();
|
|
|
|
let is_footnotes = !footnotes.is_empty();
|
|
|
|
self.footnotes.add(footnotes);
|
|
|
|
is_footnotes
|
|
|
|
}
|
2019-11-05 08:10:48 +02:00
|
|
|
}
|
2022-01-02 19:18:04 +02:00
|
|
|
|
2023-03-16 11:48:24 +02:00
|
|
|
fn collect_dependencies_in_paragraph(
|
|
|
|
paragraph: &Paragraph,
|
|
|
|
comments: &mut Vec<Comment>,
|
|
|
|
comments_extended: &mut Vec<CommentExtended>,
|
|
|
|
comment_map: &mut HashMap<usize, String>,
|
|
|
|
hyperlink_map: &mut HashMap<String, String>,
|
|
|
|
) {
|
|
|
|
for child in ¶graph.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
push_comment_and_comment_extended(comments, comments_extended, comment_map, c);
|
|
|
|
}
|
|
|
|
if let ParagraphChild::Hyperlink(h) = child {
|
|
|
|
if let HyperlinkData::External { rid, path } = h.link.clone() {
|
|
|
|
hyperlink_map.insert(rid, path);
|
|
|
|
};
|
|
|
|
for child in &h.children {
|
|
|
|
if let ParagraphChild::CommentStart(c) = child {
|
|
|
|
push_comment_and_comment_extended(comments, comments_extended, comment_map, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-06 04:47:15 +03:00
|
|
|
fn collect_dependencies_in_table(
|
2022-06-14 12:36:54 +03:00
|
|
|
table: &Table,
|
|
|
|
comments: &mut Vec<Comment>,
|
|
|
|
comments_extended: &mut Vec<CommentExtended>,
|
|
|
|
comment_map: &mut HashMap<usize, String>,
|
2022-07-06 04:47:15 +03:00
|
|
|
hyperlink_map: &mut HashMap<String, String>,
|
2022-06-14 12:36:54 +03:00
|
|
|
) {
|
|
|
|
for TableChild::TableRow(row) in &table.rows {
|
|
|
|
for TableRowChild::TableCell(cell) in &row.cells {
|
|
|
|
for content in &cell.children {
|
|
|
|
match content {
|
|
|
|
TableCellContent::Paragraph(paragraph) => {
|
2023-03-16 11:48:24 +02:00
|
|
|
collect_dependencies_in_paragraph(
|
|
|
|
paragraph,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
2022-06-14 12:36:54 +03:00
|
|
|
}
|
2022-07-06 04:47:15 +03:00
|
|
|
TableCellContent::Table(table) => collect_dependencies_in_table(
|
|
|
|
table,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
),
|
2023-03-16 11:48:24 +02:00
|
|
|
TableCellContent::StructuredDataTag(tag) => {
|
|
|
|
for child in &tag.children {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
collect_dependencies_in_paragraph(
|
|
|
|
paragraph,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
collect_dependencies_in_table(
|
|
|
|
table,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TableCellContent::TableOfContents(t) => {
|
|
|
|
for child in &t.before_contents {
|
|
|
|
if let TocContent::Paragraph(paragraph) = child {
|
|
|
|
collect_dependencies_in_paragraph(
|
|
|
|
paragraph,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let TocContent::Table(table) = child {
|
|
|
|
collect_dependencies_in_table(
|
|
|
|
table,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for child in &t.after_contents {
|
|
|
|
if let TocContent::Paragraph(paragraph) = child {
|
|
|
|
collect_dependencies_in_paragraph(
|
|
|
|
paragraph,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if let TocContent::Table(table) = child {
|
|
|
|
collect_dependencies_in_table(
|
|
|
|
table,
|
|
|
|
comments,
|
|
|
|
comments_extended,
|
|
|
|
comment_map,
|
|
|
|
hyperlink_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn store_comments_in_paragraph(paragraph: &mut Paragraph, comments: &[Comment]) {
|
|
|
|
for child in &mut paragraph.children {
|
|
|
|
if let ParagraphChild::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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let ParagraphChild::Insert(ref mut insert) = child {
|
|
|
|
for child in &mut insert.children {
|
|
|
|
if let InsertChild::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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2022-06-14 12:36:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn store_comments_in_table(table: &mut Table, comments: &[Comment]) {
|
|
|
|
for TableChild::TableRow(row) in &mut table.rows {
|
|
|
|
for TableRowChild::TableCell(cell) in &mut row.cells {
|
|
|
|
for content in &mut cell.children {
|
|
|
|
match content {
|
|
|
|
TableCellContent::Paragraph(paragraph) => {
|
2023-03-16 11:48:24 +02:00
|
|
|
store_comments_in_paragraph(paragraph, comments)
|
|
|
|
}
|
|
|
|
TableCellContent::Table(ref mut table) => {
|
|
|
|
store_comments_in_table(table, comments);
|
|
|
|
}
|
|
|
|
TableCellContent::StructuredDataTag(ref mut tag) => {
|
|
|
|
for child in &mut tag.children {
|
|
|
|
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
|
|
|
store_comments_in_paragraph(paragraph, comments);
|
2022-06-14 12:36:54 +03:00
|
|
|
}
|
2023-03-16 11:48:24 +02:00
|
|
|
if let StructuredDataTagChild::Table(table) = child {
|
|
|
|
store_comments_in_table(table, comments);
|
2022-06-14 12:36:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-16 11:48:24 +02:00
|
|
|
TableCellContent::TableOfContents(ref mut t) => {
|
|
|
|
for child in &mut t.before_contents {
|
|
|
|
if let TocContent::Paragraph(paragraph) = child {
|
|
|
|
store_comments_in_paragraph(paragraph, comments);
|
|
|
|
}
|
|
|
|
if let TocContent::Table(table) = child {
|
|
|
|
store_comments_in_table(table, comments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for child in &mut t.after_contents {
|
|
|
|
if let TocContent::Paragraph(paragraph) = child {
|
|
|
|
store_comments_in_paragraph(paragraph, comments);
|
|
|
|
}
|
|
|
|
if let TocContent::Table(table) = child {
|
|
|
|
store_comments_in_table(table, comments);
|
|
|
|
}
|
|
|
|
}
|
2022-06-14 12:36:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_comment_and_comment_extended(
|
|
|
|
comments: &mut Vec<Comment>,
|
|
|
|
comments_extended: &mut Vec<CommentExtended>,
|
|
|
|
comment_map: &HashMap<usize, String>,
|
|
|
|
c: &CommentRangeStart,
|
|
|
|
) {
|
|
|
|
let comment = c.get_comment();
|
|
|
|
for child in comment.children {
|
|
|
|
if let CommentChild::Paragraph(child) = child {
|
|
|
|
let para_id = child.id.clone();
|
|
|
|
comments.push(c.get_comment());
|
|
|
|
let comment_extended = CommentExtended::new(para_id);
|
|
|
|
if let Some(parent_comment_id) = comment.parent_comment_id {
|
2022-07-22 05:46:07 +03:00
|
|
|
if let Some(parent_para_id) = comment_map.get(&parent_comment_id) {
|
2022-08-09 09:32:17 +03:00
|
|
|
comments_extended
|
|
|
|
.push(comment_extended.parent_paragraph_id(parent_para_id.clone()));
|
2022-07-22 05:46:07 +03:00
|
|
|
}
|
2022-06-14 12:36:54 +03:00
|
|
|
} else {
|
|
|
|
comments_extended.push(comment_extended);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: Support table in comment
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-02 19:18:04 +02:00
|
|
|
fn update_document_by_toc(
|
|
|
|
document_children: Vec<DocumentChild>,
|
|
|
|
styles: &Styles,
|
|
|
|
toc: TableOfContents,
|
|
|
|
toc_index: usize,
|
|
|
|
) -> Vec<DocumentChild> {
|
|
|
|
let heading_map = styles.create_heading_style_map();
|
|
|
|
let mut items = vec![];
|
|
|
|
let mut children = vec![];
|
2022-01-10 17:39:38 +02:00
|
|
|
let style_map: std::collections::HashMap<String, usize> = toc
|
|
|
|
.instr
|
|
|
|
.styles_with_levels
|
|
|
|
.iter()
|
|
|
|
.map(|sl| sl.0.clone())
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
if toc.instr.heading_styles_range.is_none() && !toc.instr.styles_with_levels.is_empty() {
|
|
|
|
// INFO: if \t option set without heading styles ranges, Microsoft word does not show ToC items...
|
|
|
|
return document_children;
|
|
|
|
}
|
|
|
|
|
|
|
|
let (min, max) = toc.instr.heading_styles_range.unwrap_or((0, 9));
|
2022-01-02 19:18:04 +02:00
|
|
|
|
|
|
|
for child in document_children.into_iter() {
|
|
|
|
match child {
|
|
|
|
DocumentChild::Paragraph(mut paragraph) => {
|
|
|
|
if let Some(heading_level) = paragraph
|
|
|
|
.property
|
|
|
|
.style
|
|
|
|
.as_ref()
|
|
|
|
.map(|p| p.val.to_string())
|
|
|
|
.and_then(|sid| heading_map.get(&sid))
|
|
|
|
{
|
2022-01-10 17:39:38 +02:00
|
|
|
if min <= *heading_level && max >= *heading_level {
|
2022-01-06 09:13:45 +02:00
|
|
|
let toc_key = TocKey::generate();
|
|
|
|
items.push(
|
|
|
|
TableOfContentsItem::new()
|
|
|
|
.text(paragraph.raw_text())
|
|
|
|
.toc_key(&toc_key)
|
|
|
|
.level(*heading_level),
|
|
|
|
);
|
2022-03-28 13:40:32 +03:00
|
|
|
paragraph =
|
|
|
|
Box::new(paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key));
|
2022-01-02 19:18:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some((_min, _max)) = toc.instr.tc_field_level_range {
|
|
|
|
// TODO: check tc field
|
|
|
|
}
|
|
|
|
}
|
2022-01-10 17:39:38 +02:00
|
|
|
|
|
|
|
// Support \t option. Collect toc items if style id matched.
|
|
|
|
if let Some(level) = paragraph
|
|
|
|
.property
|
|
|
|
.style
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|s| style_map.get(&s.val))
|
|
|
|
{
|
|
|
|
if min <= *level && max >= *level {
|
|
|
|
let toc_key = TocKey::generate();
|
|
|
|
items.push(
|
|
|
|
TableOfContentsItem::new()
|
|
|
|
.text(paragraph.raw_text())
|
|
|
|
.toc_key(&toc_key)
|
|
|
|
.level(*level),
|
|
|
|
);
|
2022-03-28 13:40:32 +03:00
|
|
|
paragraph =
|
|
|
|
Box::new(paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key));
|
2022-01-10 17:39:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-02 19:18:04 +02:00
|
|
|
children.push(DocumentChild::Paragraph(paragraph));
|
|
|
|
}
|
|
|
|
DocumentChild::Table(ref _table) => {
|
|
|
|
// TODO:
|
|
|
|
// for row in &table.rows {
|
|
|
|
// for cell in &row.cells {
|
|
|
|
// for content in &cell.children {
|
|
|
|
// match content {
|
|
|
|
// TableCellContent::Paragraph(paragraph) => {}
|
|
|
|
// TableCellContent::Table(_) => {
|
|
|
|
// // TODO: Support table in table
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
children.push(child);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
children.push(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut toc = toc;
|
|
|
|
toc.items = items;
|
2022-03-28 13:40:32 +03:00
|
|
|
children[toc_index] = DocumentChild::TableOfContents(Box::new(toc));
|
2022-01-02 19:18:04 +02:00
|
|
|
children
|
|
|
|
}
|