fix: add before/after contents and with_instr_text in toc (#582)

* fix

* refactor js

* fix: add before/after contents in toc

* fix

* fix
main
bokuweb 2022-12-13 13:33:48 +09:00 committed by GitHub
parent c4f9ba0e7e
commit 7f2dace81c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 703 additions and 427 deletions

View File

@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## docx-wasm@0.0.276-rc39 (13. Dec, 2022)
- Support before/after contents in ToC.
- Support Toc from instrText.
## docx-wasm@0.0.276-rc38 (7. Dec, 2022) ## docx-wasm@0.0.276-rc38 (7. Dec, 2022)
- fix #584 Remove `%` from width. - fix #584 Remove `%` from width.

View File

@ -71,6 +71,10 @@ impl InstrToC {
Self::default() Self::default()
} }
pub fn with_instr_text(s: &str) -> Self {
Self::from_str(s).expect("should convert to InstrToC")
}
pub fn heading_styles_range(mut self, start: usize, end: usize) -> Self { pub fn heading_styles_range(mut self, start: usize, end: usize) -> Self {
self.heading_styles_range = Some((start, end)); self.heading_styles_range = Some((start, end));
self self
@ -429,4 +433,18 @@ mod tests {
.add_style_with_level(StyleWithLevel::new("MySpectacularStyle2", 4)) .add_style_with_level(StyleWithLevel::new("MySpectacularStyle2", 4))
); );
} }
#[test]
fn with_instr_text() {
let s = r#"TOC \o "1-3" \h \z \u"#;
let i = InstrToC::with_instr_text(s);
assert_eq!(
i,
InstrToC::new()
.heading_styles_range(1, 3)
.use_applied_paragraph_line_level()
.hide_tab_and_page_numbers_in_webview()
.hyperlink()
);
}
} }

View File

@ -142,6 +142,11 @@ impl StructuredDataTag {
self.property = self.property.data_binding(d); self.property = self.property.data_binding(d);
self self
} }
pub fn alias(mut self, v: impl Into<String>) -> Self {
self.property = self.property.alias(v);
self
}
} }
impl BuildXML for StructuredDataTag { impl BuildXML for StructuredDataTag {

View File

@ -1,9 +1,38 @@
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize; use serde::Serialize;
use crate::documents::*; use crate::documents::*;
use crate::types::*; use crate::types::*;
use crate::xml_builder::*; use crate::xml_builder::*;
#[derive(Debug, Clone, PartialEq)]
pub enum TocContent {
Paragraph(Box<Paragraph>),
Table(Box<Table>),
}
impl Serialize for TocContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
TocContent::Paragraph(ref p) => {
let mut t = serializer.serialize_struct("Paragraph", 2)?;
t.serialize_field("type", "paragraph")?;
t.serialize_field("data", p)?;
t.end()
}
TocContent::Table(ref c) => {
let mut t = serializer.serialize_struct("Table", 2)?;
t.serialize_field("type", "table")?;
t.serialize_field("data", c)?;
t.end()
}
}
}
}
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TOCTOC_topic_ID0ELZO1.html // https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TOCTOC_topic_ID0ELZO1.html
// This struct is only used by writers // This struct is only used by writers
#[derive(Serialize, Debug, Clone, PartialEq, Default)] #[derive(Serialize, Debug, Clone, PartialEq, Default)]
@ -14,6 +43,12 @@ pub struct TableOfContents {
pub dirty: bool, pub dirty: bool,
pub alias: Option<String>, pub alias: Option<String>,
pub page_ref_placeholder: Option<String>, pub page_ref_placeholder: Option<String>,
// it is inserted in before toc.
#[serde(skip_serializing_if = "Vec::is_empty")]
pub before_contents: Vec<TocContent>,
// it is inserted in after toc.
#[serde(skip_serializing_if = "Vec::is_empty")]
pub after_contents: Vec<TocContent>,
} }
impl TableOfContents { impl TableOfContents {
@ -21,6 +56,14 @@ impl TableOfContents {
Self::default() Self::default()
} }
pub fn with_instr_text(s: &str) -> Self {
let instr = InstrToC::with_instr_text(s);
Self {
instr,
..Self::default()
}
}
pub fn heading_styles_range(mut self, start: usize, end: usize) -> Self { pub fn heading_styles_range(mut self, start: usize, end: usize) -> Self {
self.instr = self.instr.heading_styles_range(start, end); self.instr = self.instr.heading_styles_range(start, end);
self self
@ -60,6 +103,27 @@ impl TableOfContents {
self.dirty = true; self.dirty = true;
self self
} }
pub fn add_before_paragraph(mut self, p: Paragraph) -> Self {
self.before_contents
.push(TocContent::Paragraph(Box::new(p)));
self
}
pub fn add_after_paragraph(mut self, p: Paragraph) -> Self {
self.after_contents.push(TocContent::Paragraph(Box::new(p)));
self
}
pub fn add_before_table(mut self, t: Table) -> Self {
self.before_contents.push(TocContent::Table(Box::new(t)));
self
}
pub fn add_after_table(mut self, t: Table) -> Self {
self.after_contents.push(TocContent::Table(Box::new(t)));
self
}
} }
impl BuildXML for TableOfContents { impl BuildXML for TableOfContents {
@ -77,15 +141,36 @@ impl BuildXML for TableOfContents {
); );
let p2 = Paragraph::new().add_run(Run::new().add_field_char(FieldCharType::End, false)); let p2 = Paragraph::new().add_run(Run::new().add_field_char(FieldCharType::End, false));
XMLBuilder::new() let mut b = XMLBuilder::new()
.open_structured_tag() .open_structured_tag()
.add_child(&p) .add_child(&p)
.open_structured_tag_content() .open_structured_tag_content();
.add_child(&p1)
.add_child(&p2) for c in self.before_contents.iter() {
.close() match c {
.close() TocContent::Paragraph(p) => {
.build() b = b.add_child(p);
}
TocContent::Table(t) => {
b = b.add_child(t);
}
}
}
b = b.add_child(&p1).add_child(&p2);
for c in self.after_contents.iter() {
match c {
TocContent::Paragraph(p) => {
b = b.add_child(p);
}
TocContent::Table(t) => {
b = b.add_child(t);
}
}
}
b.close().close().build()
} else { } else {
let items: Vec<TableOfContentsItem> = self let items: Vec<TableOfContentsItem> = self
.items .items
@ -100,14 +185,37 @@ impl BuildXML for TableOfContents {
item item
}) })
.collect(); .collect();
XMLBuilder::new()
let mut b = XMLBuilder::new()
.open_structured_tag() .open_structured_tag()
.add_child(&p) .add_child(&p)
.open_structured_tag_content() .open_structured_tag_content();
.add_child(&items)
.close() for c in self.before_contents.iter() {
.close() match c {
.build() TocContent::Paragraph(p) => {
b = b.add_child(p);
}
TocContent::Table(t) => {
b = b.add_child(t);
}
}
}
b = b.add_child(&items);
for c in self.after_contents.iter() {
match c {
TocContent::Paragraph(p) => {
b = b.add_child(p);
}
TocContent::Table(t) => {
b = b.add_child(t);
}
}
}
b.close().close().build()
} }
} }
} }

View File

@ -2,6 +2,8 @@ use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum DocxError { pub enum DocxError {
#[error("FromStr error.{0}")]
ConvertError(String),
#[error("Failed to write XML to buffer.")] #[error("Failed to write XML to buffer.")]
EmitterError(#[from] xml::writer::Error), EmitterError(#[from] xml::writer::Error),
#[error("Failed to zip XML documents.")] #[error("Failed to zip XML documents.")]

View File

@ -1,6 +1,8 @@
import { Paragraph } from "./paragraph"; import { Paragraph } from "./paragraph";
import { Table } from "./table"; import { Table } from "./table";
import * as wasm from "./pkg";
export class Comment { export class Comment {
id: number; id: number;
_author: string; _author: string;
@ -31,4 +33,25 @@ export class Comment {
this._parentCommentId = id; this._parentCommentId = id;
return this; return this;
} }
build() {
let comment = wasm.createComment(this.id);
this.children.forEach((child) => {
if (child instanceof Paragraph) {
comment = comment.add_paragraph(child.build());
} else if (child instanceof Table) {
// TODO: Support later
}
});
if (this._author) {
comment = comment.author(this._author);
}
if (this._date) {
comment = comment.date(this._date);
}
if (this._parentCommentId) {
comment = comment.parent_comment_id(this._parentCommentId);
}
return comment;
}
} }

View File

@ -1,5 +1,7 @@
import { Run } from "./run"; import { Run } from "./run";
import * as wasm from "./pkg";
export class Delete { export class Delete {
run: Run; run: Run;
@ -19,4 +21,16 @@ export class Delete {
this._date = date; this._date = date;
return this; return this;
} }
build() {
const run = this.run.build();
let del = wasm.createDelete(run);
if (this._author) {
del = del.author(this._author);
}
if (this._date) {
del = del.date(this._date);
}
return del;
}
} }

View File

@ -55,6 +55,34 @@ export class Hyperlink {
this.children.push(end); this.children.push(end);
return this; return this;
} }
build() {
let hyperlink = wasm.createHyperlink(this.v, convertHyperlinkType(this));
this.children.forEach((child) => {
if (child instanceof Run) {
const run = child.build();
hyperlink = hyperlink.add_run(run);
} else if (child instanceof Insert) {
const insert = child.build();
hyperlink = hyperlink.add_insert(insert);
} else if (child instanceof Delete) {
const del = child.build();
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 = child.build();
hyperlink = hyperlink.add_comment_start(comment);
} else if (child instanceof CommentEnd) {
hyperlink = hyperlink.add_comment_end(child.id);
}
});
return hyperlink;
}
} }
export const convertHyperlinkType = (link: Hyperlink): wasm.HyperlinkType => { export const convertHyperlinkType = (link: Hyperlink): wasm.HyperlinkType => {

View File

@ -1,18 +1,8 @@
import { Paragraph } from "./paragraph"; import { Paragraph } from "./paragraph";
import { ParagraphProperty, setParagraphProperty } from "./paragraph-property"; import { ParagraphProperty } from "./paragraph-property";
import { Insert } from "./insert"; import { Table } from "./table";
import { Delete } from "./delete";
import { convertHyperlinkType, Hyperlink } from "./hyperlink";
import { DeleteText } from "./delete-text";
import { setTableProperty, Table } from "./table";
import { TableOfContents } from "./table-of-contents"; import { TableOfContents } from "./table-of-contents";
import { TableCell, toTextDirectionWasmType } from "./table-cell"; import { RunFonts } from "./run";
import { convertBorderType, Run, RunFonts, setRunProperty } from "./run";
import { Text } from "./text";
import { Tab } from "./tab";
import { Break } from "./break";
import { Comment } from "./comment";
import { CommentEnd } from "./comment-end";
import { AbstractNumbering } from "./abstract-numbering"; import { AbstractNumbering } from "./abstract-numbering";
import { Numbering } from "./numbering"; import { Numbering } from "./numbering";
import { BookmarkStart } from "./bookmark-start"; import { BookmarkStart } from "./bookmark-start";
@ -24,7 +14,6 @@ import { Styles } from "./styles";
import { WebExtension } from "./webextension"; import { WebExtension } from "./webextension";
import { Footer } from "./footer"; import { Footer } from "./footer";
import { Header } from "./header"; import { Header } from "./header";
import { Image } from "./image";
import { import {
SectionProperty, SectionProperty,
@ -44,6 +33,7 @@ export class Docx {
| BookmarkEnd | BookmarkEnd
| TableOfContents | TableOfContents
)[] = []; )[] = [];
hasNumberings = false; hasNumberings = false;
abstractNumberings: AbstractNumbering[] = []; abstractNumberings: AbstractNumbering[] = [];
numberings: Numbering[] = []; numberings: Numbering[] = [];
@ -233,122 +223,6 @@ export class Docx {
return f; return f;
}; };
buildRun(r: Run) {
let run = wasm.createRun();
r.children.forEach((child) => {
if (child instanceof Text) {
run = run.add_text(child.text);
} else if (child instanceof DeleteText) {
run = run.add_delete_text(child.text);
} else if (child instanceof Tab) {
run = run.add_tab();
} else if (child instanceof Break) {
if (child.type === "column") {
run = run.add_break(wasm.BreakType.Column);
} else if (child.type === "page") {
run = run.add_break(wasm.BreakType.Page);
} else if (child.type === "textWrapping") {
run = run.add_break(wasm.BreakType.TextWrapping);
}
} else if (child instanceof Image) {
let pic = wasm.createPic(child.data);
if (child.w != null && child.h != null) {
pic = pic.size(child.w, child.h);
}
if (child._floating) {
pic = pic.floating();
}
if (child._offsetX != null) {
pic = pic.offset_x(child._offsetX);
}
if (child._offsetY != null) {
pic = pic.offset_x(child._offsetY);
}
if (child.rot != null) {
pic = pic.rotate(child.rot);
}
run = run.add_image(pic);
}
});
run = setRunProperty(run, r.property) as wasm.Run;
return run;
}
buildHyperlink(link: Hyperlink) {
let hyperlink = wasm.createHyperlink(link.v, convertHyperlinkType(link));
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);
if (i._author) {
insert = insert.author(i._author);
}
if (i._date) {
insert = insert.date(i._date);
}
return insert;
}
buildDelete(d: Delete) {
const run = this.buildRun(d.run);
let del = wasm.createDelete(run);
if (d._author) {
del = del.author(d._author);
}
if (d._date) {
del = del.date(d._date);
}
return del;
}
buildComment(c: Comment) {
let comment = wasm.createComment(c.id);
c.children.forEach((child) => {
if (child instanceof Paragraph) {
comment = comment.add_paragraph(this.buildParagraph(child));
} else if (child instanceof Table) {
// TODO:
}
});
if (c._author) {
comment = comment.author(c._author);
}
if (c._date) {
comment = comment.date(c._date);
}
if (c._parentCommentId) {
comment = comment.parent_comment_id(c._parentCommentId);
}
return comment;
}
buildLineSpacing(p: ParagraphProperty): wasm.LineSpacing | null { buildLineSpacing(p: ParagraphProperty): wasm.LineSpacing | null {
const { lineSpacing } = p; const { lineSpacing } = p;
if (lineSpacing == null) return null; if (lineSpacing == null) return null;
@ -394,267 +268,6 @@ export class Docx {
return spacing; return spacing;
} }
buildParagraph(p: Paragraph) {
let paragraph = wasm.createParagraph();
p.children.forEach((child) => {
if (child instanceof Run) {
const run = this.buildRun(child);
paragraph = paragraph.add_run(run);
} else if (child instanceof Insert) {
const insert = this.buildInsert(child);
paragraph = paragraph.add_insert(insert);
} 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) {
paragraph = paragraph.add_bookmark_end(child.id);
} else if (child instanceof Comment) {
const comment = this.buildComment(child);
paragraph = paragraph.add_comment_start(comment);
} else if (child instanceof CommentEnd) {
paragraph = paragraph.add_comment_end(child.id);
}
});
paragraph = setParagraphProperty(paragraph, p.property);
if (typeof p.property.styleId !== "undefined") {
paragraph = paragraph.style(p.property.styleId);
}
if (p.property.runProperty.del) {
paragraph = paragraph.delete(
p.property.runProperty.del.author,
p.property.runProperty.del.date
);
}
if (p.property.runProperty.ins) {
paragraph = paragraph.insert(
p.property.runProperty.ins.author,
p.property.runProperty.ins.date
);
}
if (p.property.paragraphPropertyChange) {
let change = wasm.createParagraphPropertyChange();
change = change
.author(p.property.paragraphPropertyChange._author)
.date(p.property.paragraphPropertyChange._date);
if (p.property.paragraphPropertyChange._property.numbering) {
change = change.numbering(
p.property.paragraphPropertyChange._property.numbering.id,
p.property.paragraphPropertyChange._property.numbering.level
);
}
// TODO: add style, indent, alignment
paragraph = paragraph.paragraph_property_change(change);
}
return paragraph;
}
buildTable(t: Table) {
let table = wasm.createTable();
t.rows.forEach((r) => {
let row = wasm.createTableRow();
r.cells.forEach((c) => {
const cell = this.buildCell(c);
row = row.add_cell(cell);
});
if (r.height) {
row = row.row_height(r.height);
}
if (r.del) {
row = row.delete(r.del.author, r.del.date);
}
if (r.ins) {
row = row.insert(r.ins.author, r.ins.date);
}
if (r.hRule) {
switch (r.hRule) {
case "auto": {
row = row.height_rule(wasm.HeightRule.Auto);
break;
}
case "atLeast": {
row = row.height_rule(wasm.HeightRule.AtLeast);
break;
}
case "exact": {
row = row.height_rule(wasm.HeightRule.Exact);
break;
}
}
}
table = table.add_row(row);
});
table = table.set_grid(new Uint32Array(t.grid));
if (t.property.styleId) {
table = table.style(t.property.styleId);
}
table = setTableProperty(table, t.property);
return table;
}
buildCell(c: TableCell) {
let cell = wasm.createTableCell();
c.children.forEach((c) => {
if (c instanceof Paragraph) {
const paragraph = this.buildParagraph(c);
cell = cell.add_paragraph(paragraph);
} else if (c instanceof Table) {
const table = this.buildTable(c);
cell = cell.add_table(table);
}
});
if (c.property.verticalMerge === "continue") {
cell = cell.vertical_merge(wasm.VMergeType.Continue);
} else if (c.property.verticalMerge === "restart") {
cell = cell.vertical_merge(wasm.VMergeType.Restart);
}
switch (c.property.verticalAlign) {
case "top": {
cell = cell.vertical_align(wasm.VAlignType.Top);
break;
}
case "center": {
cell = cell.vertical_align(wasm.VAlignType.Center);
break;
}
case "bottom": {
cell = cell.vertical_align(wasm.VAlignType.Bottom);
break;
}
}
if (typeof c.property.gridSpan !== "undefined") {
cell = cell.grid_span(c.property.gridSpan);
}
if (typeof c.property.width !== "undefined") {
cell = cell.width(c.property.width);
}
if (typeof c.property.textDirection !== "undefined") {
cell = cell.text_direction(
toTextDirectionWasmType(c.property.textDirection)
);
}
if (typeof c.property.borders !== "undefined") {
cell = this.buildCellBorders(c, cell);
}
if (typeof c.property.shading !== "undefined") {
cell = cell.shading(
c.property.shading._type,
c.property.shading._color,
c.property.shading._fill
);
}
return cell;
}
buildCellBorders(js: TableCell, cell: wasm.TableCell): wasm.TableCell {
if (js.property.borders.top) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Top)
.size(js.property.borders.top._size)
.color(js.property.borders.top._color)
.border_type(convertBorderType(js.property.borders.top._border_type));
cell = cell.set_border(border);
}
if (js.property.borders.right) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Right)
.size(js.property.borders.right._size)
.color(js.property.borders.right._color)
.border_type(convertBorderType(js.property.borders.right._border_type));
cell = cell.set_border(border);
}
if (js.property.borders.bottom) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Bottom)
.size(js.property.borders.bottom._size)
.color(js.property.borders.bottom._color)
.border_type(
convertBorderType(js.property.borders.bottom._border_type)
);
cell = cell.set_border(border);
}
if (js.property.borders.left) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Left)
.size(js.property.borders.left._size)
.color(js.property.borders.left._color)
.border_type(convertBorderType(js.property.borders.left._border_type));
cell = cell.set_border(border);
}
if (js.property.borders.insideH) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.InsideH)
.size(js.property.borders.insideH._size)
.color(js.property.borders.insideH._color)
.border_type(
convertBorderType(js.property.borders.insideH._border_type)
);
cell = cell.set_border(border);
}
if (js.property.borders.insideV) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.InsideV)
.size(js.property.borders.insideV._size)
.color(js.property.borders.insideV._color)
.border_type(
convertBorderType(js.property.borders.insideV._border_type)
);
cell = cell.set_border(border);
}
if (js.property.borders.tl2br) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Tl2br)
.size(js.property.borders.tl2br._size)
.color(js.property.borders.tl2br._color)
.border_type(convertBorderType(js.property.borders.tl2br._border_type));
cell = cell.set_border(border);
}
if (js.property.borders.tr2bl) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Tr2bl)
.size(js.property.borders.tr2bl._size)
.color(js.property.borders.tr2bl._color)
.border_type(convertBorderType(js.property.borders.tr2bl._border_type));
cell = cell.set_border(border);
}
return cell;
}
buildLevel(l: Level) { buildLevel(l: Level) {
let level = wasm.createLevel(l.id, l.start, l.format, l.text, l.jc); let level = wasm.createLevel(l.id, l.start, l.format, l.text, l.jc);
@ -716,10 +329,10 @@ export class Docx {
this.children.forEach((child) => { this.children.forEach((child) => {
if (child instanceof Paragraph) { if (child instanceof Paragraph) {
let p = this.buildParagraph(child); let p = child.build();
docx = docx.add_paragraph(p); docx = docx.add_paragraph(p);
} else if (child instanceof Table) { } else if (child instanceof Table) {
let t = this.buildTable(child); let t = child.build();
docx = docx.add_table(t); docx = docx.add_table(t);
} else if (child instanceof BookmarkStart) { } else if (child instanceof BookmarkStart) {
docx = docx.add_bookmark_start(child.id, child.name); docx = docx.add_bookmark_start(child.id, child.name);
@ -779,9 +392,9 @@ export class Docx {
let header = wasm.createHeader(); let header = wasm.createHeader();
this.sectionProperty._header.children.forEach((c) => { this.sectionProperty._header.children.forEach((c) => {
if (c instanceof Paragraph) { if (c instanceof Paragraph) {
header = header.add_paragraph(this.buildParagraph(c)); header = header.add_paragraph(c.build());
} else { } else {
header = header.add_table(this.buildTable(c)); header = header.add_table(c.build());
} }
}); });
docx = docx.header(header); docx = docx.header(header);
@ -791,9 +404,9 @@ export class Docx {
let header = wasm.createHeader(); let header = wasm.createHeader();
this.sectionProperty._firstHeader.children.forEach((c) => { this.sectionProperty._firstHeader.children.forEach((c) => {
if (c instanceof Paragraph) { if (c instanceof Paragraph) {
header = header.add_paragraph(this.buildParagraph(c)); header = header.add_paragraph(c.build());
} else { } else {
header = header.add_table(this.buildTable(c)); header = header.add_table(c.build());
} }
}); });
docx = docx.first_header(header); docx = docx.first_header(header);
@ -803,9 +416,9 @@ export class Docx {
let header = wasm.createHeader(); let header = wasm.createHeader();
this.sectionProperty._evenHeader.children.forEach((c) => { this.sectionProperty._evenHeader.children.forEach((c) => {
if (c instanceof Paragraph) { if (c instanceof Paragraph) {
header = header.add_paragraph(this.buildParagraph(c)); header = header.add_paragraph(c.build());
} else { } else {
header = header.add_table(this.buildTable(c)); header = header.add_table(c.build());
} }
}); });
docx = docx.even_header(header); docx = docx.even_header(header);
@ -815,9 +428,9 @@ export class Docx {
let footer = wasm.createFooter(); let footer = wasm.createFooter();
this.sectionProperty._footer.children.forEach((c) => { this.sectionProperty._footer.children.forEach((c) => {
if (c instanceof Paragraph) { if (c instanceof Paragraph) {
footer = footer.add_paragraph(this.buildParagraph(c)); footer = footer.add_paragraph(c.build());
} else { } else {
footer = footer.add_table(this.buildTable(c)); footer = footer.add_table(c.build());
} }
}); });
docx = docx.footer(footer); docx = docx.footer(footer);
@ -827,9 +440,9 @@ export class Docx {
let footer = wasm.createFooter(); let footer = wasm.createFooter();
this.sectionProperty._firstFooter.children.forEach((c) => { this.sectionProperty._firstFooter.children.forEach((c) => {
if (c instanceof Paragraph) { if (c instanceof Paragraph) {
footer = footer.add_paragraph(this.buildParagraph(c)); footer = footer.add_paragraph(c.build());
} else { } else {
footer = footer.add_table(this.buildTable(c)); footer = footer.add_table(c.build());
} }
}); });
docx = docx.first_footer(footer); docx = docx.first_footer(footer);
@ -839,9 +452,9 @@ export class Docx {
let footer = wasm.createFooter(); let footer = wasm.createFooter();
this.sectionProperty._evenFooter.children.forEach((c) => { this.sectionProperty._evenFooter.children.forEach((c) => {
if (c instanceof Paragraph) { if (c instanceof Paragraph) {
footer = footer.add_paragraph(this.buildParagraph(c)); footer = footer.add_paragraph(c.build());
} else { } else {
footer = footer.add_table(this.buildTable(c)); footer = footer.add_table(c.build());
} }
}); });
docx = docx.even_footer(footer); docx = docx.even_footer(footer);

View File

@ -1,5 +1,7 @@
import { Run } from "./run"; import { Run } from "./run";
import * as wasm from "./pkg";
export class Insert { export class Insert {
run: Run; run: Run;
_author: string | null = null; _author: string | null = null;
@ -17,4 +19,16 @@ export class Insert {
this._date = date; this._date = date;
return this; return this;
} }
build() {
const run = this.run.build();
let insert = wasm.createInsert(run);
if (this._author) {
insert = insert.author(this._author);
}
if (this._date) {
insert = insert.date(this._date);
}
return insert;
}
} }

View File

@ -6,6 +6,7 @@ import {
AlignmentType, AlignmentType,
SpecialIndentKind, SpecialIndentKind,
ParagraphPropertyChange, ParagraphPropertyChange,
setParagraphProperty,
} from "./paragraph-property"; } from "./paragraph-property";
import { Insert } from "./insert"; import { Insert } from "./insert";
import { Delete } from "./delete"; import { Delete } from "./delete";
@ -15,6 +16,8 @@ import { Comment } from "./comment";
import { CommentEnd } from "./comment-end"; import { CommentEnd } from "./comment-end";
import { Hyperlink } from "./hyperlink"; import { Hyperlink } from "./hyperlink";
import * as wasm from "./pkg";
export type ParagraphChild = export type ParagraphChild =
| Run | Run
| Insert | Insert
@ -155,4 +158,70 @@ export class Paragraph {
this.property.paragraphPropertyChange = propertyChange; this.property.paragraphPropertyChange = propertyChange;
return this; return this;
} }
build() {
let paragraph = wasm.createParagraph();
this.children.forEach((child) => {
if (child instanceof Run) {
const run = child.build();
paragraph = paragraph.add_run(run);
} else if (child instanceof Insert) {
const insert = child.build();
paragraph = paragraph.add_insert(insert);
} else if (child instanceof Delete) {
const del = child.build();
paragraph = paragraph.add_delete(del);
} else if (child instanceof Hyperlink) {
const hyperlink = child.build();
paragraph = paragraph.add_hyperlink(hyperlink);
} else if (child instanceof BookmarkStart) {
paragraph = paragraph.add_bookmark_start(child.id, child.name);
} else if (child instanceof BookmarkEnd) {
paragraph = paragraph.add_bookmark_end(child.id);
} else if (child instanceof Comment) {
const comment = child.build();
paragraph = paragraph.add_comment_start(comment);
} else if (child instanceof CommentEnd) {
paragraph = paragraph.add_comment_end(child.id);
}
});
paragraph = setParagraphProperty(paragraph, this.property);
if (typeof this.property.styleId !== "undefined") {
paragraph = paragraph.style(this.property.styleId);
}
if (this.property.runProperty.del) {
paragraph = paragraph.delete(
this.property.runProperty.del.author,
this.property.runProperty.del.date
);
}
if (this.property.runProperty.ins) {
paragraph = paragraph.insert(
this.property.runProperty.ins.author,
this.property.runProperty.ins.date
);
}
if (this.property.paragraphPropertyChange) {
let change = wasm.createParagraphPropertyChange();
change = change
.author(this.property.paragraphPropertyChange._author)
.date(this.property.paragraphPropertyChange._date);
if (this.property.paragraphPropertyChange._property.numbering) {
change = change.numbering(
this.property.paragraphPropertyChange._property.numbering.id,
this.property.paragraphPropertyChange._property.numbering.level
);
}
// TODO: add style, indent, alignment
paragraph = paragraph.paragraph_property_change(change);
}
return paragraph;
}
} }

View File

@ -280,6 +280,49 @@ export class Run {
}; };
return this; return this;
} }
build() {
let run = wasm.createRun();
this.children.forEach((child) => {
if (child instanceof Text) {
run = run.add_text(child.text);
} else if (child instanceof DeleteText) {
run = run.add_delete_text(child.text);
} else if (child instanceof Tab) {
run = run.add_tab();
} else if (child instanceof Break) {
if (child.type === "column") {
run = run.add_break(wasm.BreakType.Column);
} else if (child.type === "page") {
run = run.add_break(wasm.BreakType.Page);
} else if (child.type === "textWrapping") {
run = run.add_break(wasm.BreakType.TextWrapping);
}
} else if (child instanceof Image) {
let pic = wasm.createPic(child.data);
if (child.w != null && child.h != null) {
pic = pic.size(child.w, child.h);
}
if (child._floating) {
pic = pic.floating();
}
if (child._offsetX != null) {
pic = pic.offset_x(child._offsetX);
}
if (child._offsetY != null) {
pic = pic.offset_x(child._offsetY);
}
if (child.rot != null) {
pic = pic.rotate(child.rot);
}
run = run.add_image(pic);
}
});
run = setRunProperty(run, this.property) as wasm.Run;
return run;
}
} }
export const setRunProperty = <T extends wasm.Run | wasm.Style>( export const setRunProperty = <T extends wasm.Run | wasm.Style>(

View File

@ -4,6 +4,7 @@ import { Shading } from "./shading";
import { TableCellBorders, PositionKeys } from "./table-cell-borders"; import { TableCellBorders, PositionKeys } from "./table-cell-borders";
import { TableCellBorderPosition, TableCellBorder } from "./table-cell-border"; import { TableCellBorderPosition, TableCellBorder } from "./table-cell-border";
import * as wasm from "./pkg"; import * as wasm from "./pkg";
import { convertBorderType } from "./run";
export type VMergeType = "restart" | "continue"; export type VMergeType = "restart" | "continue";
@ -118,16 +119,166 @@ export class TableCell {
} }
setBorder(border: TableCellBorder) { setBorder(border: TableCellBorder) {
this.property.borders[ this.property.borders[border.position.toLowerCase() as PositionKeys] =
border.position.toLowerCase() as PositionKeys border;
] = border;
return this; return this;
} }
clearBorder(position: TableCellBorderPosition) { clearBorder(position: TableCellBorderPosition) {
this.property.borders[ this.property.borders[position.toLowerCase() as PositionKeys] =
position.toLowerCase() as PositionKeys new TableCellBorder(position).border_type("nil");
] = new TableCellBorder(position).border_type("nil");
return this; return this;
} }
buildCellBorders(cell: wasm.TableCell): wasm.TableCell {
if (this.property.borders.top) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Top)
.size(this.property.borders.top._size)
.color(this.property.borders.top._color)
.border_type(convertBorderType(this.property.borders.top._border_type));
cell = cell.set_border(border);
}
if (this.property.borders.right) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Right)
.size(this.property.borders.right._size)
.color(this.property.borders.right._color)
.border_type(
convertBorderType(this.property.borders.right._border_type)
);
cell = cell.set_border(border);
}
if (this.property.borders.bottom) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Bottom)
.size(this.property.borders.bottom._size)
.color(this.property.borders.bottom._color)
.border_type(
convertBorderType(this.property.borders.bottom._border_type)
);
cell = cell.set_border(border);
}
if (this.property.borders.left) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Left)
.size(this.property.borders.left._size)
.color(this.property.borders.left._color)
.border_type(
convertBorderType(this.property.borders.left._border_type)
);
cell = cell.set_border(border);
}
if (this.property.borders.insideH) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.InsideH)
.size(this.property.borders.insideH._size)
.color(this.property.borders.insideH._color)
.border_type(
convertBorderType(this.property.borders.insideH._border_type)
);
cell = cell.set_border(border);
}
if (this.property.borders.insideV) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.InsideV)
.size(this.property.borders.insideV._size)
.color(this.property.borders.insideV._color)
.border_type(
convertBorderType(this.property.borders.insideV._border_type)
);
cell = cell.set_border(border);
}
if (this.property.borders.tl2br) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Tl2br)
.size(this.property.borders.tl2br._size)
.color(this.property.borders.tl2br._color)
.border_type(
convertBorderType(this.property.borders.tl2br._border_type)
);
cell = cell.set_border(border);
}
if (this.property.borders.tr2bl) {
const border = wasm
.createTableCellBorder(wasm.TableCellBorderPosition.Tr2bl)
.size(this.property.borders.tr2bl._size)
.color(this.property.borders.tr2bl._color)
.border_type(
convertBorderType(this.property.borders.tr2bl._border_type)
);
cell = cell.set_border(border);
}
return cell;
}
build() {
let cell = wasm.createTableCell();
this.children.forEach((c) => {
if (c instanceof Paragraph) {
const paragraph = c.build();
cell = cell.add_paragraph(paragraph);
} else if (c instanceof Table) {
const table = c.build();
cell = cell.add_table(table);
}
});
if (this.property.verticalMerge === "continue") {
cell = cell.vertical_merge(wasm.VMergeType.Continue);
} else if (this.property.verticalMerge === "restart") {
cell = cell.vertical_merge(wasm.VMergeType.Restart);
}
switch (this.property.verticalAlign) {
case "top": {
cell = cell.vertical_align(wasm.VAlignType.Top);
break;
}
case "center": {
cell = cell.vertical_align(wasm.VAlignType.Center);
break;
}
case "bottom": {
cell = cell.vertical_align(wasm.VAlignType.Bottom);
break;
}
}
if (typeof this.property.gridSpan !== "undefined") {
cell = cell.grid_span(this.property.gridSpan);
}
if (typeof this.property.width !== "undefined") {
cell = cell.width(this.property.width);
}
if (typeof this.property.textDirection !== "undefined") {
cell = cell.text_direction(
toTextDirectionWasmType(this.property.textDirection)
);
}
if (typeof this.property.borders !== "undefined") {
cell = this.buildCellBorders(cell);
}
if (typeof this.property.shading !== "undefined") {
cell = cell.shading(
this.property.shading._type,
this.property.shading._color,
this.property.shading._fill
);
}
return cell;
}
} }

View File

@ -1,8 +1,11 @@
import { Paragraph } from "./paragraph";
import * as wasm from "./pkg"; import * as wasm from "./pkg";
import { Table } from "./table";
import { TableOfContentsItem } from "./table-of-contents-item"; import { TableOfContentsItem } from "./table-of-contents-item";
export class TableOfContents { export class TableOfContents {
_instrText?: string;
_headingStylesRange: [number, number] | null = null; _headingStylesRange: [number, number] | null = null;
_styleWithLevels: { styleId: string; level: number }[] = []; _styleWithLevels: { styleId: string; level: number }[] = [];
_hyperlink = false; _hyperlink = false;
@ -11,6 +14,32 @@ export class TableOfContents {
_dirty = false; _dirty = false;
_items: TableOfContentsItem[] = []; _items: TableOfContentsItem[] = [];
_pageRefPlaceholder = ""; _pageRefPlaceholder = "";
_beforeContents: (Paragraph | Table)[] = [];
_afterContents: (Paragraph | Table)[] = [];
constructor(instrText?: string) {
this._instrText = instrText;
}
addBeforeParagraph(p: Paragraph) {
this._beforeContents.push(p);
return this;
}
addBeforeTable(t: Table) {
this._beforeContents.push(t);
return this;
}
addAfterParagraph(p: Paragraph) {
this._afterContents.push(p);
return this;
}
addAfterTable(t: Table) {
this._afterContents.push(t);
return this;
}
headingStylesRange = (r: [number, number]) => { headingStylesRange = (r: [number, number]) => {
this._headingStylesRange = r; this._headingStylesRange = r;
@ -53,7 +82,9 @@ export class TableOfContents {
}; };
buildWasmObject = () => { buildWasmObject = () => {
let toc = wasm.createTableOfContents(); let toc = this._instrText
? wasm.createTableOfContentsWithInstrText(this._instrText)
: wasm.createTableOfContents();
if (this._headingStylesRange) { if (this._headingStylesRange) {
toc = toc.heading_styles_range( toc = toc.heading_styles_range(
this._headingStylesRange[0], this._headingStylesRange[0],
@ -89,6 +120,22 @@ export class TableOfContents {
toc = toc.add_item(item.buildWasmObject()); toc = toc.add_item(item.buildWasmObject());
} }
for (const c of this._beforeContents) {
if (c instanceof Paragraph) {
toc = toc.add_before_paragraph(c.build());
} else if (c instanceof Table) {
toc = toc.add_before_table(c.build());
}
}
for (const c of this._afterContents) {
if (c instanceof Paragraph) {
toc = toc.add_after_paragraph(c.build());
} else if (c instanceof Table) {
toc = toc.add_after_table(c.build());
}
}
return toc; return toc;
}; };
} }

View File

@ -104,6 +104,57 @@ export class Table {
this.property.cellMargins.bottom = { val: v, type: t }; this.property.cellMargins.bottom = { val: v, type: t };
return this; return this;
} }
build() {
let table = wasm.createTable();
this.rows.forEach((r) => {
let row = wasm.createTableRow();
r.cells.forEach((c) => {
const cell = c.build();
row = row.add_cell(cell);
});
if (r.height) {
row = row.row_height(r.height);
}
if (r.del) {
row = row.delete(r.del.author, r.del.date);
}
if (r.ins) {
row = row.insert(r.ins.author, r.ins.date);
}
if (r.hRule) {
switch (r.hRule) {
case "auto": {
row = row.height_rule(wasm.HeightRule.Auto);
break;
}
case "atLeast": {
row = row.height_rule(wasm.HeightRule.AtLeast);
break;
}
case "exact": {
row = row.height_rule(wasm.HeightRule.Exact);
break;
}
}
}
table = table.add_row(row);
});
table = table.set_grid(new Uint32Array(this.grid));
if (this.property.styleId) {
table = table.style(this.property.styleId);
}
table = setTableProperty(table, this.property);
return table;
}
} }
export const convertWidthType = (t: string) => { export const convertWidthType = (t: string) => {

View File

@ -1,6 +1,6 @@
{ {
"name": "docx-wasm", "name": "docx-wasm",
"version": "0.0.276-rc38", "version": "0.0.276-rc39",
"main": "dist/node/index.js", "main": "dist/node/index.js",
"browser": "dist/web/index.js", "browser": "dist/web/index.js",
"author": "bokuweb <bokuweb12@gmail.com>", "author": "bokuweb <bokuweb12@gmail.com>",

View File

@ -11,6 +11,11 @@ pub fn create_table_of_contents() -> TableOfContents {
TableOfContents(docx_rs::TableOfContents::new()) TableOfContents(docx_rs::TableOfContents::new())
} }
#[wasm_bindgen(js_name = createTableOfContentsWithInstrText)]
pub fn create_table_of_contents_with_instr_text(s: &str) -> TableOfContents {
TableOfContents(docx_rs::TableOfContents::with_instr_text(s))
}
impl TableOfContents { impl TableOfContents {
pub fn take(self) -> docx_rs::TableOfContents { pub fn take(self) -> docx_rs::TableOfContents {
self.0 self.0
@ -61,4 +66,24 @@ impl TableOfContents {
self.0.dirty = true; self.0.dirty = true;
self self
} }
pub fn add_before_paragraph(mut self, p: Paragraph) -> Self {
self.0 = self.0.add_before_paragraph(p.take());
self
}
pub fn add_after_paragraph(mut self, p: Paragraph) -> Self {
self.0 = self.0.add_after_paragraph(p.take());
self
}
pub fn add_before_table(mut self, t: Table) -> Self {
self.0 = self.0.add_before_table(t.take());
self
}
pub fn add_after_table(mut self, t: Table) -> Self {
self.0 = self.0.add_after_table(t.take());
self
}
} }

View File

@ -151916,6 +151916,27 @@ Object {
} }
`; `;
exports[`writer should write ToC with instrText 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 ToC with instrText 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:sdt><w:sdtPr><w:rPr /><w:alias w:val=\\"Table of contents\\" />
</w:sdtPr><w:sdtContent><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Before contents</w:t></w:r></w:p><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType=\\"begin\\" w:dirty=\\"true\\" /><w:instrText>TOC \\\\u</w:instrText><w:fldChar w:fldCharType=\\"separate\\" w:dirty=\\"false\\" /></w:r></w:p><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:fldChar w:fldCharType=\\"end\\" w:dirty=\\"false\\" /></w:r></w:p><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">After contents</w:t></w:r></w:p></w:sdtContent>
</w:sdt><w:p w14:paraId=\\"00000003\\"><w:pPr><w:rPr /><w:pStyle w:val=\\"Heading1\\" /><w:pageBreakBefore />
</w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello!!</w:t></w:r></w:p><w:p w14:paraId=\\"00000004\\"><w:pPr><w:rPr /><w:pStyle w:val=\\"Heading2\\" /><w:pageBreakBefore />
</w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">World</w:t></w:r></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:num=\\"1\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /></w:sectPr></w:body>
</w:document>"
`;
exports[`writer should write ToC with items 1`] = ` exports[`writer should write ToC with items 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?> "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\"> <Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
@ -152780,7 +152801,7 @@ exports[`writer should write paragraph delete 1`] = `
exports[`writer should write paragraph delete 2`] = ` exports[`writer should write paragraph delete 2`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?> "<?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: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:del w:id=\\"0\\" w:author=\\"bokuweb\\" w:date=\\"2021-12-23T18:16:00Z\\" /></w:rPr><w:numPr><w:numId w:val=\\"1\\" /><w:ilvl w:val=\\"0\\" /></w:numPr></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello world!!</w:t></w:r></w:p><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /><w:numPr><w:numId w:val=\\"1\\" /><w:ilvl w:val=\\"0\\" /></w:numPr></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Foo</w:t></w:r></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:num=\\"1\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /></w:sectPr></w:body> <w:body><w:p w14:paraId=\\"00000003\\"><w:pPr><w:rPr><w:del w:id=\\"0\\" w:author=\\"bokuweb\\" w:date=\\"2021-12-23T18:16:00Z\\" /></w:rPr><w:numPr><w:numId w:val=\\"1\\" /><w:ilvl w:val=\\"0\\" /></w:numPr></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello world!!</w:t></w:r></w:p><w:p w14:paraId=\\"00000004\\"><w:pPr><w:rPr /><w:numPr><w:numId w:val=\\"1\\" /><w:ilvl w:val=\\"0\\" /></w:numPr></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Foo</w:t></w:r></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:num=\\"1\\" /><w:docGrid w:type=\\"lines\\" w:linePitch=\\"360\\" /></w:sectPr></w:body>
</w:document>" </w:document>"
`; `;

View File

@ -756,6 +756,45 @@ describe("writer", () => {
} }
}); });
test("should write ToC with instrText", () => {
const before = new w.Paragraph().addRun(
new w.Run().addText("Before contents")
);
const after = new w.Paragraph().addRun(
new w.Run().addText("After contents")
);
const p1 = new w.Paragraph()
.addRun(new w.Run().addText("Hello!!"))
.pageBreakBefore(true)
.style("Heading1");
const style1 = new w.Style("Heading1", "paragraph").name("Heading 1");
const p2 = new w.Paragraph()
.addRun(new w.Run().addText("World"))
.pageBreakBefore(true)
.style("Heading2");
const style2 = new w.Style("Heading2", "paragraph").name("Heading 2");
const buffer = new w.Docx()
.addTableOfContents(
new w.TableOfContents(`TOC \o "1-3" \h \z \\u`)
.alias("Table of contents")
.addBeforeParagraph(before)
.addAfterParagraph(after)
.dirty()
)
.addParagraph(p1)
.addParagraph(p2)
.addStyle(style1)
.addStyle(style2)
.build();
writeFileSync("../output/js/toc_with_instr_text.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();
}
}
});
test("should write paragraph delete", () => { test("should write paragraph delete", () => {
const p1 = new w.Paragraph() const p1 = new w.Paragraph()
.addRun(new w.Run().addText("Hello world!!")) .addRun(new w.Run().addText("Hello world!!"))