11// http://officeopenxml.com/WPtableOfContents.php
22// http://www.datypic.com/sc/ooxml/e-w_sdt-1.html
33import { FileChild } from "@file/file-child" ;
4- import { Paragraph } from "@file/paragraph" ;
5- import { Run } from "@file/paragraph/run" ;
4+ import { InternalHyperlink , Paragraph , TabStopDefinition } from "@file/paragraph" ;
5+ import { Run , Tab } from "@file/paragraph/run" ;
66import { Begin , End , Separate } from "@file/paragraph/run/field" ;
7+ import { Text } from "@file/paragraph/run/run-components/text" ;
78
89import { FieldInstruction } from "./field-instruction" ;
910import { StructuredDocumentTagContent } from "./sdt-content" ;
1011import { StructuredDocumentTagProperties } from "./sdt-properties" ;
1112import { ITableOfContentsOptions } from "./table-of-contents-properties" ;
1213
14+ type ToCEntry = {
15+ readonly title : string ;
16+ readonly level : number ;
17+ readonly page ?: number ;
18+ readonly href ?: string ;
19+ } ;
20+
1321export class TableOfContents extends FileChild {
14- public constructor ( alias : string = "Table of Contents" , properties ?: ITableOfContentsOptions ) {
22+ public constructor ( alias : string = "Table of Contents" , properties ?: ITableOfContentsOptions , cachedContent : readonly ToCEntry [ ] = [ ] ) {
1523 super ( "w:sdt" ) ;
1624 this . root . push ( new StructuredDocumentTagProperties ( alias ) ) ;
1725
1826 const content = new StructuredDocumentTagContent ( ) ;
1927
28+ const beginParagraphChildren =
29+ cachedContent . length >= 1 ? [ this . buildCachedContentParagraphChild ( cachedContent [ 0 ] , properties ) ] : [ ] ;
30+
31+ const getTabStops = ( level : number ) : readonly TabStopDefinition [ ] => {
32+ const levelSpace = 720 ;
33+ const levelPosition = 9025 - ( level - 1 ) * levelSpace ; // TODO: should be equal to page width - level margin
34+ return [
35+ {
36+ type : "clear" ,
37+ position : levelPosition ,
38+ } ,
39+ {
40+ type : "right" ,
41+ position : 9025 , // TODO: should be equal to page width
42+ leader : "dot" ,
43+ } ,
44+ ] ;
45+ } ;
46+
2047 const beginParagraph = new Paragraph ( {
48+ style : cachedContent . length >= 1 ? `TOC${ cachedContent [ 0 ] . level } ` : undefined ,
49+ tabStops : getTabStops ( cachedContent . length >= 1 ? cachedContent [ 0 ] . level : 1 ) ,
2150 children : [
2251 new Run ( {
2352 children : [ new Begin ( true ) , new FieldInstruction ( properties ) , new Separate ( ) ] ,
2453 } ) ,
54+ ...beginParagraphChildren ,
2555 ] ,
2656 } ) ;
2757
2858 content . addChildElement ( beginParagraph ) ;
2959
60+ const middleParagraphs = cachedContent . slice ( 1 , - 1 ) . map ( ( entry ) => new Paragraph ( {
61+ style : `TOC${ entry . level } ` ,
62+ tabStops : getTabStops ( entry . level ) ,
63+ children : [ this . buildCachedContentParagraphChild ( entry , properties ) ] ,
64+ } ) ) ;
65+
66+ for ( const paragraph of middleParagraphs ) {
67+ content . addChildElement ( paragraph ) ;
68+ }
69+
70+ const endParagraphChildren =
71+ cachedContent . length > 1 ? [ this . buildCachedContentParagraphChild ( cachedContent [ cachedContent . length - 1 ] , properties ) ] : [ ] ;
72+
3073 const endParagraph = new Paragraph ( {
74+ style : cachedContent . length > 1 ? `TOC${ cachedContent [ cachedContent . length - 1 ] . level } ` : undefined ,
75+ tabStops : getTabStops ( cachedContent . length > 1 ? cachedContent [ cachedContent . length - 1 ] . level : 1 ) ,
3176 children : [
77+ ...endParagraphChildren ,
3278 new Run ( {
3379 children : [ new End ( ) ] ,
3480 } ) ,
@@ -39,4 +85,30 @@ export class TableOfContents extends FileChild {
3985
4086 this . root . push ( content ) ;
4187 }
88+
89+ private buildCachedContentRun ( entry : ToCEntry ) : Run {
90+ return new Run ( {
91+ children : [
92+ new Text ( {
93+ text : entry . title ,
94+ } ) ,
95+ new Tab ( ) ,
96+ new Text ( {
97+ text : entry . page ?. toString ( ) ?? "" ,
98+ } ) ,
99+ ] ,
100+ } ) ;
101+ }
102+
103+ private buildCachedContentParagraphChild ( entry : ToCEntry , properties ?: ITableOfContentsOptions ) : Run | InternalHyperlink {
104+ const run = this . buildCachedContentRun ( entry ) ;
105+ if ( properties ?. hyperlink && entry . href !== undefined ) {
106+ return new InternalHyperlink ( {
107+ anchor : entry . href ,
108+ children : [ run ] ,
109+ } ) ;
110+ }
111+
112+ return run ;
113+ }
42114}
0 commit comments