parent
0f5e1d1cdc
commit
fec94fd5f5
|
@ -4,7 +4,9 @@ use crate::documents::*;
|
|||
use crate::types::*;
|
||||
use crate::xml_builder::*;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FieldChar {
|
||||
pub field_char_type: FieldCharType,
|
||||
pub dirty: bool,
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
use serde::Serialize;
|
||||
|
||||
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_HYPERLINKHYPERLINK_topic_ID0EFYG1.html
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstrHyperlink {
|
||||
pub target: String,
|
||||
// \l
|
||||
pub anchor: bool,
|
||||
}
|
||||
|
||||
impl InstrHyperlink {
|
||||
pub fn new(target: impl Into<String>) -> Self {
|
||||
Self {
|
||||
target: target.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl BuildXML for instrHyperlink {
|
||||
// fn build(&self) -> Vec<u8> {
|
||||
// TODO:
|
||||
// }
|
||||
// }
|
||||
|
||||
impl std::str::FromStr for InstrHyperlink {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(instr: &str) -> Result<Self, Self::Err> {
|
||||
let mut s = instr.split(' ');
|
||||
let mut target = "".to_string();
|
||||
let mut anchor = false;
|
||||
loop {
|
||||
if let Some(i) = s.next() {
|
||||
match i {
|
||||
"\\l" => {
|
||||
anchor = true;
|
||||
}
|
||||
"\\m" => {
|
||||
// TODO:
|
||||
}
|
||||
"\\n" => {
|
||||
// TODO:
|
||||
}
|
||||
"\\o" => {
|
||||
// TODO: Support later
|
||||
let _ = s.next();
|
||||
}
|
||||
"\\t" => {
|
||||
// TODO: Support later
|
||||
let _ = s.next();
|
||||
}
|
||||
_ => {
|
||||
target = i.replace(""", "").replace("\"", "").to_string();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME: For now, return error if target is not found
|
||||
if target.is_empty() {
|
||||
return Err(());
|
||||
}
|
||||
return Ok(Self { target, anchor });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ use crate::documents::*;
|
|||
|
||||
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_PAGEREFPAGEREF_topic_ID0EHXK1.html
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstrPAGEREF {
|
||||
pub page_ref: String,
|
||||
pub hyperlink: bool,
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::documents::*;
|
|||
|
||||
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TCTC_topic_ID0EU2N1.html
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstrTC {
|
||||
pub text: String,
|
||||
// \n Omits the page number for the entry.
|
||||
|
|
|
@ -9,6 +9,7 @@ pub enum InstrText {
|
|||
TOC(InstrToC),
|
||||
TC(InstrTC),
|
||||
PAGEREF(InstrPAGEREF),
|
||||
HYPERLINK(InstrHyperlink),
|
||||
Unsupported(String),
|
||||
}
|
||||
|
||||
|
@ -18,6 +19,7 @@ impl BuildXML for Box<InstrText> {
|
|||
InstrText::TOC(toc) => toc.build(),
|
||||
InstrText::TC(tc) => tc.build(),
|
||||
InstrText::PAGEREF(page_ref) => page_ref.build(),
|
||||
InstrText::HYPERLINK(_link) => todo!(),
|
||||
InstrText::Unsupported(s) => s.as_bytes().to_vec(),
|
||||
};
|
||||
XMLBuilder::new()
|
||||
|
@ -52,6 +54,12 @@ impl Serialize for InstrText {
|
|||
t.serialize_field("data", s)?;
|
||||
t.end()
|
||||
}
|
||||
InstrText::HYPERLINK(ref s) => {
|
||||
let mut t = serializer.serialize_struct("HYPERLINK", 2)?;
|
||||
t.serialize_field("type", "hyperlink")?;
|
||||
t.serialize_field("data", s)?;
|
||||
t.end()
|
||||
}
|
||||
InstrText::Unsupported(ref s) => {
|
||||
let mut t = serializer.serialize_struct("Unsupported", 2)?;
|
||||
t.serialize_field("type", "unsupported")?;
|
||||
|
|
|
@ -2,7 +2,8 @@ use serde::Serialize;
|
|||
|
||||
use crate::documents::*;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
pub struct StyleWithLevel(pub (String, usize));
|
||||
|
||||
impl StyleWithLevel {
|
||||
|
@ -11,7 +12,9 @@ impl StyleWithLevel {
|
|||
}
|
||||
}
|
||||
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TOCTOC_topic_ID0ELZO1.html
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, Default, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstrToC {
|
||||
// \o If no heading range is specified, all heading levels used in the document are listed.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
|
@ -34,6 +34,7 @@ mod hyperlink;
|
|||
mod indent;
|
||||
mod indent_level;
|
||||
mod insert;
|
||||
mod instr_hyperlink;
|
||||
mod instr_pageref;
|
||||
mod instr_tc;
|
||||
mod instr_text;
|
||||
|
@ -148,6 +149,7 @@ pub use hyperlink::*;
|
|||
pub use indent::*;
|
||||
pub use indent_level::*;
|
||||
pub use insert::*;
|
||||
pub use instr_hyperlink::*;
|
||||
pub use instr_pageref::*;
|
||||
pub use instr_tc::*;
|
||||
pub use instr_text::*;
|
||||
|
|
|
@ -38,6 +38,11 @@ impl ElementReader for InstrText {
|
|||
return Ok(InstrText::TC(instr));
|
||||
}
|
||||
}
|
||||
if instr.starts_with("HYPERLINK") {
|
||||
if let Ok(instr) = InstrHyperlink::from_str(instr) {
|
||||
return Ok(InstrText::HYPERLINK(instr));
|
||||
}
|
||||
}
|
||||
if instr.starts_with("PAGEREF") {
|
||||
if let Ok(instr) = InstrPAGEREF::from_str(instr) {
|
||||
return Ok(InstrText::PAGEREF(instr));
|
||||
|
|
|
@ -10,7 +10,9 @@ use wasm_bindgen::prelude::*;
|
|||
use super::errors;
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum FieldCharType {
|
||||
Begin,
|
||||
Separate,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import type { FieldCharType } from "./FieldCharType";
|
||||
|
||||
export interface FieldChar { fieldCharType: FieldCharType, dirty: boolean, }
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export type FieldCharType = "begin" | "separate" | "end" | "unsupported";
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export interface InstrHyperlink { target: string, anchor: boolean, }
|
|
@ -0,0 +1,3 @@
|
|||
import type { StyleWithLevel } from "./StyleWithLevel";
|
||||
|
||||
export interface InstrToC { headingStylesRange?: [number, number], tcFieldLevelRange?: [number, number], omitPageNumbersLevelRange?: [number, number], entryBookmarkName?: string, stylesWithLevels: Array<StyleWithLevel>, entryAndPageNumberSeparator?: string, sequenceAndPageNumbersSeparator?: string, captionLabel: string | null, captionLabelIncludingNumbers?: string, seqFieldIdentifierForPrefix?: string, tcFieldIdentifier?: string, hyperlink: boolean, preserveTab: boolean, preserveNewLine: boolean, useAppliedParagraphLineLevel: boolean, hideTabAndPageNumbersInWebview: boolean, }
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export type StyleWithLevel = [string, number];
|
|
@ -4,6 +4,9 @@ import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
|
|||
import { BorderType } from "../border";
|
||||
import { InsertJSON, DeleteJSON } from "./paragraph";
|
||||
import { VertAlignType } from "../run";
|
||||
import { FieldChar } from "./bindings/FieldChar";
|
||||
import { InstrHyperlink } from "./bindings/InstrHyperlink";
|
||||
import { InstrToC } from "./bindings/InstrToC";
|
||||
|
||||
export type TextBorderJSON = {
|
||||
borderType: BorderType;
|
||||
|
@ -53,7 +56,9 @@ export type RunChildJSON =
|
|||
| DrawingJSON
|
||||
| ShapeJSON
|
||||
| CommentRangeStartJSON
|
||||
| CommentRangeEndJSON;
|
||||
| CommentRangeEndJSON
|
||||
| FieldCharJSON
|
||||
| InstrTextJSON;
|
||||
|
||||
export type TextJSON = {
|
||||
type: "text";
|
||||
|
@ -89,3 +94,21 @@ export type RunJSON = {
|
|||
children: RunChildJSON[];
|
||||
};
|
||||
};
|
||||
|
||||
export type FieldCharJSON = {
|
||||
type: "fieldChar";
|
||||
data: FieldChar;
|
||||
};
|
||||
|
||||
export type InstrTextJSON = {
|
||||
type: "instrText";
|
||||
data:
|
||||
| {
|
||||
type: "hyperlink";
|
||||
data: InstrHyperlink;
|
||||
}
|
||||
| {
|
||||
type: "toc";
|
||||
data: InstrToC;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docx-wasm",
|
||||
"version": "0.0.276-rc4",
|
||||
"version": "0.0.276-rc7",
|
||||
"main": "dist/node/index.js",
|
||||
"browser": "dist/web/index.js",
|
||||
"author": "bokuweb <bokuweb12@gmail.com>",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -159,6 +159,12 @@ describe("reader", () => {
|
|||
const json = w.readDocx(buffer);
|
||||
expect(json).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("should read hyperlink instr", () => {
|
||||
const buffer = readFileSync("../fixtures/instr_links/instr_links.docx");
|
||||
const json = w.readDocx(buffer);
|
||||
expect(json).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("writer", () => {
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue