feat: Added a hyperlink element (#386)
* feat: Added a hyperlink element * feat: fix comment collerctor * feat: Add JS APImain
parent
a4ddb3a5ee
commit
26edc02635
|
@ -0,0 +1,24 @@
|
|||
use docx_rs::*;
|
||||
|
||||
pub fn main() -> Result<(), DocxError> {
|
||||
let path = std::path::Path::new("./output/hyperlink.docx");
|
||||
let file = std::fs::File::create(&path).unwrap();
|
||||
Docx::new()
|
||||
.add_paragraph(
|
||||
Paragraph::new().add_hyperlink(
|
||||
Hyperlink::new()
|
||||
.anchor("anchor")
|
||||
.add_run(Run::new().add_text("Hello")),
|
||||
),
|
||||
)
|
||||
.add_bookmark_start(1, "anchor")
|
||||
.add_paragraph(
|
||||
Paragraph::new()
|
||||
.add_run(Run::new().add_text("World"))
|
||||
.page_break_before(true),
|
||||
)
|
||||
.add_bookmark_end(1)
|
||||
.build()
|
||||
.pack(file)?;
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use super::*;
|
||||
use crate::documents::BuildXML;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default)]
|
||||
pub struct Hyperlink {
|
||||
pub rid: Option<String>,
|
||||
pub anchor: Option<String>,
|
||||
pub history: bool,
|
||||
pub children: Vec<ParagraphChild>,
|
||||
}
|
||||
|
||||
impl Hyperlink {
|
||||
pub fn new() -> Self {
|
||||
Hyperlink::default()
|
||||
}
|
||||
|
||||
pub fn rid(mut self, rid: impl Into<String>) -> Self {
|
||||
self.rid = Some(rid.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn anchor(mut self, anchor: impl Into<String>) -> Self {
|
||||
self.anchor = Some(anchor.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn history(mut self) -> Self {
|
||||
self.history = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_run(mut self, run: Run) -> Self {
|
||||
self.children.push(ParagraphChild::Run(Box::new(run)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Self {
|
||||
self.children
|
||||
.push(ParagraphChild::StructuredDataTag(Box::new(t)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_insert(mut self, insert: Insert) -> Self {
|
||||
self.children.push(ParagraphChild::Insert(insert));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_delete(mut self, delete: Delete) -> Self {
|
||||
self.children.push(ParagraphChild::Delete(delete));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_bookmark_start(mut self, id: usize, name: impl Into<String>) -> Self {
|
||||
self.children
|
||||
.push(ParagraphChild::BookmarkStart(BookmarkStart::new(id, name)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_bookmark_end(mut self, id: usize) -> Self {
|
||||
self.children
|
||||
.push(ParagraphChild::BookmarkEnd(BookmarkEnd::new(id)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_comment_start(mut self, comment: Comment) -> Self {
|
||||
self.children.push(ParagraphChild::CommentStart(Box::new(
|
||||
CommentRangeStart::new(comment),
|
||||
)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_comment_end(mut self, id: usize) -> Self {
|
||||
self.children
|
||||
.push(ParagraphChild::CommentEnd(CommentRangeEnd::new(id)));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for Hyperlink {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let b = XMLBuilder::new();
|
||||
b.open_hyperlink(self.rid.as_ref(), self.anchor.as_ref(), self.history)
|
||||
.add_children(&self.children)
|
||||
.close()
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
#[cfg(test)]
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_hyperlink() {
|
||||
let l = Hyperlink::new()
|
||||
.anchor("ToC1")
|
||||
.add_run(Run::new().add_text("hello"));
|
||||
let b = l.build();
|
||||
assert_eq!(
|
||||
str::from_utf8(&b).unwrap(),
|
||||
r#"<w:hyperlink w:anchor="ToC1"><w:r><w:rPr /><w:t xml:space="preserve">hello</w:t></w:r></w:hyperlink>"#
|
||||
);
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ mod footer_reference;
|
|||
mod grid_span;
|
||||
mod header_reference;
|
||||
mod highlight;
|
||||
mod hyperlink;
|
||||
mod indent;
|
||||
mod indent_level;
|
||||
mod insert;
|
||||
|
@ -135,6 +136,7 @@ pub use footer_reference::*;
|
|||
pub use grid_span::*;
|
||||
pub use header_reference::*;
|
||||
pub use highlight::*;
|
||||
pub use hyperlink::*;
|
||||
pub use indent::*;
|
||||
pub use indent_level::*;
|
||||
pub use insert::*;
|
||||
|
|
|
@ -32,6 +32,7 @@ pub enum ParagraphChild {
|
|||
Insert(Insert),
|
||||
Delete(Delete),
|
||||
BookmarkStart(BookmarkStart),
|
||||
Hyperlink(Hyperlink),
|
||||
BookmarkEnd(BookmarkEnd),
|
||||
CommentStart(Box<CommentRangeStart>),
|
||||
CommentEnd(CommentRangeEnd),
|
||||
|
@ -44,6 +45,7 @@ impl BuildXML for ParagraphChild {
|
|||
ParagraphChild::Run(v) => v.build(),
|
||||
ParagraphChild::Insert(v) => v.build(),
|
||||
ParagraphChild::Delete(v) => v.build(),
|
||||
ParagraphChild::Hyperlink(v) => v.build(),
|
||||
ParagraphChild::BookmarkStart(v) => v.build(),
|
||||
ParagraphChild::BookmarkEnd(v) => v.build(),
|
||||
ParagraphChild::CommentStart(v) => v.build(),
|
||||
|
@ -77,6 +79,12 @@ impl Serialize for ParagraphChild {
|
|||
t.serialize_field("data", r)?;
|
||||
t.end()
|
||||
}
|
||||
ParagraphChild::Hyperlink(ref r) => {
|
||||
let mut t = serializer.serialize_struct("hyperlink", 2)?;
|
||||
t.serialize_field("type", "hyperlink")?;
|
||||
t.serialize_field("data", r)?;
|
||||
t.end()
|
||||
}
|
||||
ParagraphChild::BookmarkStart(ref r) => {
|
||||
let mut t = serializer.serialize_struct("BookmarkStart", 2)?;
|
||||
t.serialize_field("type", "bookmarkStart")?;
|
||||
|
@ -130,6 +138,11 @@ impl Paragraph {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_hyperlink(mut self, link: Hyperlink) -> Self {
|
||||
self.children.push(ParagraphChild::Hyperlink(link));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Self {
|
||||
self.children
|
||||
.push(ParagraphChild::StructuredDataTag(Box::new(t)));
|
||||
|
|
|
@ -487,6 +487,46 @@ impl Docx {
|
|||
crate::reset_para_id();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
// TODO: Support table
|
||||
}
|
||||
}
|
||||
|
||||
fn push_comment_and_comment_extended(
|
||||
&self,
|
||||
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 {
|
||||
let parent_para_id = comment_map.get(&parent_comment_id).unwrap().clone();
|
||||
comments_extended.push(comment_extended.parent_paragraph_id(parent_para_id));
|
||||
} else {
|
||||
comments_extended.push(comment_extended);
|
||||
}
|
||||
}
|
||||
// TODO: Support table
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse and clone comments from document and add to comments node.
|
||||
fn update_comments(&mut self) {
|
||||
let mut comments: Vec<Comment> = vec![];
|
||||
|
@ -498,14 +538,13 @@ impl Docx {
|
|||
DocumentChild::Paragraph(paragraph) => {
|
||||
for child in ¶graph.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
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());
|
||||
self.insert_comment_to_map(&mut comment_map, c);
|
||||
}
|
||||
if let ParagraphChild::Hyperlink(h) = child {
|
||||
for child in &h.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
self.insert_comment_to_map(&mut comment_map, c);
|
||||
}
|
||||
// TODO: Support table
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -518,15 +557,16 @@ impl Docx {
|
|||
TableCellContent::Paragraph(paragraph) => {
|
||||
for child in ¶graph.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
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());
|
||||
self.insert_comment_to_map(&mut comment_map, c);
|
||||
}
|
||||
if let ParagraphChild::Hyperlink(h) = child {
|
||||
for child in &h.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
self.insert_comment_to_map(
|
||||
&mut comment_map,
|
||||
c,
|
||||
);
|
||||
}
|
||||
// TODO: Support table
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -548,23 +588,23 @@ impl Docx {
|
|||
DocumentChild::Paragraph(paragraph) => {
|
||||
for child in ¶graph.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
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 {
|
||||
let parent_para_id =
|
||||
comment_map.get(&parent_comment_id).unwrap().clone();
|
||||
comments_extended.push(
|
||||
comment_extended.parent_paragraph_id(parent_para_id),
|
||||
);
|
||||
} else {
|
||||
comments_extended.push(comment_extended);
|
||||
}
|
||||
self.push_comment_and_comment_extended(
|
||||
&mut comments,
|
||||
&mut comments_extended,
|
||||
&comment_map,
|
||||
c,
|
||||
);
|
||||
}
|
||||
if let ParagraphChild::Hyperlink(h) = child {
|
||||
for child in &h.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
self.push_comment_and_comment_extended(
|
||||
&mut comments,
|
||||
&mut comments_extended,
|
||||
&comment_map,
|
||||
c,
|
||||
);
|
||||
}
|
||||
// TODO: Support table
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -577,30 +617,22 @@ impl Docx {
|
|||
TableCellContent::Paragraph(paragraph) => {
|
||||
for child in ¶graph.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
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
|
||||
{
|
||||
let parent_para_id = comment_map
|
||||
.get(&parent_comment_id)
|
||||
.unwrap()
|
||||
.clone();
|
||||
comments_extended.push(
|
||||
comment_extended
|
||||
.parent_paragraph_id(
|
||||
parent_para_id,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
comments_extended
|
||||
.push(comment_extended);
|
||||
}
|
||||
self.push_comment_and_comment_extended(
|
||||
&mut comments,
|
||||
&mut comments_extended,
|
||||
&comment_map,
|
||||
c,
|
||||
);
|
||||
}
|
||||
if let ParagraphChild::Hyperlink(h) = child {
|
||||
for child in &h.children {
|
||||
if let ParagraphChild::CommentStart(c) = child {
|
||||
self.push_comment_and_comment_extended(
|
||||
&mut comments,
|
||||
&mut comments_extended,
|
||||
&comment_map,
|
||||
c,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,26 @@ impl XMLBuilder {
|
|||
self.close()
|
||||
}
|
||||
|
||||
pub(crate) fn open_hyperlink(
|
||||
mut self,
|
||||
rid: Option<&String>,
|
||||
anchor: Option<&String>,
|
||||
history: bool,
|
||||
) -> Self {
|
||||
let mut e = XmlEvent::start_element("w:hyperlink");
|
||||
if let Some(rid) = rid {
|
||||
e = e.attr("w:rid", rid);
|
||||
}
|
||||
if let Some(anchor) = anchor {
|
||||
e = e.attr("w:anchor", anchor);
|
||||
}
|
||||
if history {
|
||||
e = e.attr("w:history", "true");
|
||||
}
|
||||
self.writer.write(e).expect(EXPECT_MESSAGE);
|
||||
self
|
||||
}
|
||||
|
||||
// i.e. <w:r ... >
|
||||
open!(open_run, "w:r");
|
||||
open!(open_run_property, "w:rPr");
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import { Run } from "./run";
|
||||
import { Insert } from "./insert";
|
||||
import { Delete } from "./delete";
|
||||
import { BookmarkStart } from "./bookmark-start";
|
||||
import { BookmarkEnd } from "./bookmark-end";
|
||||
import { Comment } from "./comment";
|
||||
import { CommentEnd } from "./comment-end";
|
||||
import { ParagraphChild } from "./paragraph";
|
||||
|
||||
export class Hyperlink {
|
||||
_rid?: string;
|
||||
_anchor?: string;
|
||||
_history: boolean = false;
|
||||
children: ParagraphChild[] = [];
|
||||
|
||||
addRun(run: Run) {
|
||||
this.children.push(run);
|
||||
return this;
|
||||
}
|
||||
|
||||
addInsert(ins: Insert) {
|
||||
this.children.push(ins);
|
||||
return this;
|
||||
}
|
||||
|
||||
addDelete(del: Delete) {
|
||||
this.children.push(del);
|
||||
return this;
|
||||
}
|
||||
|
||||
addBookmarkStart(id: number, name: string) {
|
||||
this.children.push(new BookmarkStart(id, name));
|
||||
return this;
|
||||
}
|
||||
|
||||
addBookmarkEnd(id: number) {
|
||||
this.children.push(new BookmarkEnd(id));
|
||||
return this;
|
||||
}
|
||||
|
||||
addCommentStart(comment: Comment) {
|
||||
this.children.push(comment);
|
||||
return this;
|
||||
}
|
||||
|
||||
addCommentEnd(end: CommentEnd) {
|
||||
this.children.push(end);
|
||||
return this;
|
||||
}
|
||||
|
||||
rid(rid: string) {
|
||||
this._rid = rid;
|
||||
return this;
|
||||
}
|
||||
|
||||
anchor(anchor: string) {
|
||||
this._anchor = anchor;
|
||||
return this;
|
||||
}
|
||||
|
||||
history() {
|
||||
this._history = true;
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { Paragraph, ParagraphProperty } from "./paragraph";
|
||||
import { Insert } from "./insert";
|
||||
import { Delete } from "./delete";
|
||||
import { Hyperlink } from "./hyperlink";
|
||||
import { DeleteText } from "./delete-text";
|
||||
import { Table } from "./table";
|
||||
import { TableCell, toTextDirectionWasmType } from "./table-cell";
|
||||
|
@ -320,6 +321,43 @@ export class Docx {
|
|||
return run;
|
||||
}
|
||||
|
||||
buildHyperlink(link: Hyperlink) {
|
||||
let hyperlink = wasm.createHyperlink();
|
||||
if (link._history) {
|
||||
hyperlink = hyperlink.history();
|
||||
}
|
||||
if (link._anchor) {
|
||||
hyperlink = hyperlink.anchor(link._anchor);
|
||||
}
|
||||
if (link._rid) {
|
||||
hyperlink = hyperlink.rid(link._rid);
|
||||
}
|
||||
|
||||
link.children.forEach((child) => {
|
||||
if (child instanceof Run) {
|
||||
const run = this.buildRun(child);
|
||||
hyperlink = hyperlink.add_run(run);
|
||||
} else if (child instanceof Insert) {
|
||||
const insert = this.buildInsert(child);
|
||||
hyperlink = hyperlink.add_insert(insert);
|
||||
} else if (child instanceof Delete) {
|
||||
const del = this.buildDelete(child);
|
||||
hyperlink = hyperlink.add_delete(del);
|
||||
} else if (child instanceof BookmarkStart) {
|
||||
hyperlink = hyperlink.add_bookmark_start(child.id, child.name);
|
||||
} else if (child instanceof BookmarkEnd) {
|
||||
hyperlink = hyperlink.add_bookmark_end(child.id);
|
||||
} else if (child instanceof Comment) {
|
||||
const comment = this.buildComment(child);
|
||||
hyperlink = hyperlink.add_comment_start(comment);
|
||||
} else if (child instanceof CommentEnd) {
|
||||
hyperlink = hyperlink.add_comment_end(child.id);
|
||||
}
|
||||
});
|
||||
|
||||
return hyperlink;
|
||||
}
|
||||
|
||||
buildInsert(i: Insert) {
|
||||
const run = this.buildRun(i.run);
|
||||
let insert = wasm.createInsert(run);
|
||||
|
@ -422,6 +460,9 @@ export class Docx {
|
|||
} else if (child instanceof Delete) {
|
||||
const del = this.buildDelete(child);
|
||||
paragraph = paragraph.add_delete(del);
|
||||
} else if (child instanceof Hyperlink) {
|
||||
const hyperlink = this.buildHyperlink(child);
|
||||
paragraph = paragraph.add_hyperlink(hyperlink);
|
||||
} else if (child instanceof BookmarkStart) {
|
||||
paragraph = paragraph.add_bookmark_start(child.id, child.name);
|
||||
} else if (child instanceof BookmarkEnd) {
|
||||
|
@ -1086,6 +1127,7 @@ export * from "./run";
|
|||
export * from "./text";
|
||||
export * from "./style";
|
||||
export * from "./styles";
|
||||
export * from "./hyperlink";
|
||||
export * from "./comment";
|
||||
export * from "./comment-end";
|
||||
export * from "./numbering";
|
||||
|
|
|
@ -5,11 +5,13 @@ import { BookmarkStart } from "./bookmark-start";
|
|||
import { BookmarkEnd } from "./bookmark-end";
|
||||
import { Comment } from "./comment";
|
||||
import { CommentEnd } from "./comment-end";
|
||||
import { Hyperlink } from "./hyperlink";
|
||||
|
||||
export type ParagraphChild =
|
||||
| Run
|
||||
| Insert
|
||||
| Delete
|
||||
| Hyperlink
|
||||
| BookmarkStart
|
||||
| BookmarkEnd
|
||||
| Comment
|
||||
|
@ -102,6 +104,11 @@ export class Paragraph {
|
|||
return this;
|
||||
}
|
||||
|
||||
addHyperlink(link: Hyperlink) {
|
||||
this.children.push(link);
|
||||
return this;
|
||||
}
|
||||
|
||||
addInsert(ins: Insert) {
|
||||
this.children.push(ins);
|
||||
return this;
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Debug)]
|
||||
pub struct Hyperlink(docx_rs::Hyperlink);
|
||||
|
||||
#[wasm_bindgen(js_name = createHyperlink)]
|
||||
pub fn create_hyperlink() -> Hyperlink {
|
||||
Hyperlink(docx_rs::Hyperlink::new())
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl Hyperlink {
|
||||
pub fn rid(mut self, rid: &str) -> Self {
|
||||
self.0 = self.0.rid(rid);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn anchor(mut self, anchor: &str) -> Self {
|
||||
self.0 = self.0.anchor(anchor);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn history(mut self) -> Self {
|
||||
self.0 = self.0.history();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_run(mut self, run: Run) -> Self {
|
||||
self.0 = self.0.add_run(run.take());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_insert(mut self, i: Insert) -> Self {
|
||||
self.0
|
||||
.children
|
||||
.push(docx_rs::ParagraphChild::Insert(i.take()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_delete(mut self, d: Delete) -> Self {
|
||||
self.0
|
||||
.children
|
||||
.push(docx_rs::ParagraphChild::Delete(d.take()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_bookmark_start(mut self, id: usize, name: &str) -> Self {
|
||||
self.0.children.push(docx_rs::ParagraphChild::BookmarkStart(
|
||||
docx_rs::BookmarkStart::new(id, name),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_bookmark_end(mut self, id: usize) -> Self {
|
||||
self.0.children.push(docx_rs::ParagraphChild::BookmarkEnd(
|
||||
docx_rs::BookmarkEnd::new(id),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_comment_start(mut self, comment: Comment) -> Self {
|
||||
self.0
|
||||
.children
|
||||
.push(docx_rs::ParagraphChild::CommentStart(Box::new(
|
||||
docx_rs::CommentRangeStart::new(comment.take()),
|
||||
)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_comment_end(mut self, id: usize) -> Self {
|
||||
self.0.children.push(docx_rs::ParagraphChild::CommentEnd(
|
||||
docx_rs::CommentRangeEnd::new(id),
|
||||
));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Hyperlink {
|
||||
pub fn take(self) -> docx_rs::Hyperlink {
|
||||
self.0
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ mod delete;
|
|||
mod doc;
|
||||
mod footer;
|
||||
mod header;
|
||||
mod hyperlink;
|
||||
mod insert;
|
||||
mod level;
|
||||
mod level_override;
|
||||
|
@ -28,6 +29,7 @@ pub use delete::*;
|
|||
pub use doc::*;
|
||||
pub use footer::*;
|
||||
pub use header::*;
|
||||
pub use hyperlink::*;
|
||||
pub use insert::*;
|
||||
pub use level::*;
|
||||
pub use level_override::*;
|
||||
|
|
|
@ -17,6 +17,11 @@ impl Paragraph {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_hyperlink(mut self, link: Hyperlink) -> Paragraph {
|
||||
self.0 = self.0.add_hyperlink(link.take());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_insert(mut self, i: Insert) -> Paragraph {
|
||||
self.0
|
||||
.children
|
||||
|
|
|
@ -33241,6 +33241,24 @@ exports[`writer should write hello 3`] = `
|
|||
</w:num></w:numbering>"
|
||||
`;
|
||||
|
||||
exports[`writer should write hyperlink 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
<Relationship Id=\\"rId1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\\" Target=\\"styles.xml\\" />
|
||||
<Relationship Id=\\"rId2\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\\" Target=\\"fontTable.xml\\" />
|
||||
<Relationship Id=\\"rId3\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\\" Target=\\"settings.xml\\" />
|
||||
<Relationship Id=\\"rId5\\" Type=\\"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\\" Target=\\"commentsExtended.xml\\" />
|
||||
</Relationships>"
|
||||
`;
|
||||
|
||||
exports[`writer should write hyperlink 2`] = `
|
||||
"<?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\\" xmlns:w15=\\"http://schemas.microsoft.com/office/word/2012/wordml\\" mc:Ignorable=\\"w14 wp14\\">
|
||||
<w:body><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:hyperlink w:anchor=\\"anchor\\"><w:r><w:rPr><w:rFonts /></w:rPr><w:t xml:space=\\"preserve\\">Hello!!</w:t></w:r></w:hyperlink></w:p><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /><w:pageBreakBefore />
|
||||
</w:pPr><w:bookmarkStart w:id=\\"1\\" w:name=\\"anchor\\" /><w:r><w:rPr><w:rFonts /></w:rPr><w:t xml:space=\\"preserve\\">World!!</w:t></w:r><w:bookmarkEnd w:id=\\"1\\" /></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:cols w:space=\\"425\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /></w:sectPr></w:body>
|
||||
</w:document>"
|
||||
`;
|
||||
|
||||
exports[`writer should write line spacing 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
|
|
|
@ -442,4 +442,24 @@ describe("writer", () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("should write hyperlink", () => {
|
||||
const p1 = new w.Paragraph().addHyperlink(
|
||||
new w.Hyperlink().anchor("anchor").addRun(new w.Run().addText("Hello!!"))
|
||||
);
|
||||
const p2 = new w.Paragraph()
|
||||
.addBookmarkStart(1, "anchor")
|
||||
.addRun(new w.Run().addText("World!!"))
|
||||
.pageBreakBefore(true)
|
||||
.addBookmarkEnd(1);
|
||||
const buffer = new w.Docx().addParagraph(p1).addParagraph(p2).build();
|
||||
|
||||
writeFileSync("../output/hyperlink.docx", buffer);
|
||||
const z = new Zip(Buffer.from(buffer));
|
||||
for (const e of z.getEntries()) {
|
||||
if (e.entryName.match(/document.xml/)) {
|
||||
expect(z.readAsText(e)).toMatchSnapshot();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue