document->paragraphClose();
$params->content .= '';
// Prepare index data
$new = array();
foreach ($settings as $key => $value) {
$new [$key] = $value;
}
$new ['type'] = $type;
$new ['width'] = $params->document->getAbsWidthMindMargins();
if ($type == 'chapter') {
$new ['start_ref'] = $params->document->getPreviousToCItem(1);
} else {
$new ['start_ref'] = NULL;
}
// Add new index data
$indexesData [] = $new;
return '';
}
/**
* This function builds the actual TOC and replaces the placeholder with it.
* It is called in document_end() after all headings have been added to the TOC, see toc_additem().
* The page numbers are just a counter. Update the TOC e.g. in LibreOffice to get the real page numbers!
*
* The TOC is inserted by the syntax tag '{{odt>toc:setting=value;}};'.
* The following settings are supported:
* - Title e.g. '{{odt>toc:title=Example;}}'.
* Default is 'Table of Contents' (for english, see language files for other languages default value).
* - Leader sign, e.g. '{{odt>toc:leader-sign=.;}}'.
* Default is '.'.
* - Indents (in cm), e.g. '{{odt>toc:indents=indents=0,0.5,1,1.5,2,2.5,3;}};'.
* Default is 0.5 cm indent more per level.
* - Maximum outline/TOC level, e.g. '{{odt>toc:maxtoclevel=5;}}'.
* Default is taken from DokuWiki config setting 'maxtoclevel'.
* - Insert pagebreak after TOC, e.g. '{{odt>toc:pagebreak=1;}}'.
* Default is '1', means insert pagebreak after TOC.
* - Set style per outline/TOC level, e.g. '{{odt>toc:styleL2="color:red;font-weight:900;";}}'.
* Default is 'color:black'.
*
* It is allowed to use defaults for all settings by using '{{odt>toc}}'.
* Multiple settings can be combined, e.g. '{{odt>toc:leader-sign=.;indents=0,0.5,1,1.5,2,2.5,3;}}'.
*/
public static function replaceIndexesPlaceholders(ODTInternalParams $params, array $indexesData, array $toc) {
$index_count = count($indexesData);
for ($index_no = 0 ; $index_no < $index_count ; $index_no++) {
$data = $indexesData [$index_no];
// At the moment it does not make sense to disable links for the TOC
// because LibreOffice will insert links on updating the TOC.
$data ['create_links'] = true;
$indexContent = self::buildIndex($params->document, $toc, $data, $index_no+1);
// Replace placeholder with TOC content.
$params->content = str_replace ('', $indexContent, $params->content);
}
}
/**
* This function builds a TOC or chapter index.
* The page numbers are just a counter. Update the TOC e.g. in LibreOffice to get the real page numbers!
*
* The layout settings are taken from the configuration and $settings.
* $settings can include the following options syntax:
* - Title e.g. 'title=Example;'.
* Default is 'Table of Contents' (for english, see language files for other languages default value).
* - Leader sign, e.g. 'leader-sign=.;'.
* Default is '.'.
* - Indents (in cm), e.g. 'indents=indents=0,0.5,1,1.5,2,2.5,3;'.
* Default is 0.5 cm indent more per level.
* - Maximum outline/TOC level, e.g. 'maxtoclevel=5;'.
* Default is taken from DokuWiki config setting 'maxtoclevel'.
* - Insert pagebreak after TOC, e.g. 'pagebreak=1;'.
* Default is '1', means insert pagebreak after TOC.
* - Set style per outline/TOC level, e.g. 'styleL2="color:red;font-weight:900;";'.
* Default is 'color:black'.
*
* It is allowed to use defaults for all settings by omitting $settings.
* Multiple settings can be combined, e.g. 'leader-sign=.;indents=0,0.5,1,1.5,2,2.5,3;'.
*/
protected static function buildIndex(ODTDocument $doc, array $toc, array $settings, $indexNo) {
$stylesL = array();
$stylesLNames = array();
// Get index type
$type = $settings ['type'];
// It seems to be not supported in ODT to have a different start
// outline level than 1.
$max_outline_level = 10;
if (!empty($settings ['maxlevel'])) {
$max_outline_level = $settings ['maxlevel'];
}
// Determine title, default for table of contents is 'Table of Contents'.
// Default for chapter index is empty.
// Syntax for 'Test' as title would be "title=test;".
$title = '';
if (!empty($settings ['title'])) {
$title = $settings ['title'];
}
// Determine leader-sign, default is '.'.
// Syntax for '.' as leader-sign would be "leader_sign=.;".
$leader_sign = '.';
if (!empty($settings ['leader_sign'])) {
$leader_sign = $settings ['leader_sign'];
}
// Determine indents, default is '0.5' (cm) per level.
// Syntax for a indent of '0.5' for 5 levels would be "indents=0,0.5,1,1.5,2;".
// The values are absolute for each level, not relative to the higher level.
$indents = '0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5';
if (!empty($settings ['indents'])) {
$indents = $settings ['indents'];
}
// Determine pagebreak, default is on '1'.
// Syntax for pagebreak off would be "pagebreak=0;".
$pagebreak = true;
if (!empty($settings ['pagebreak'])) {
$temp = $settings ['pagebreak'];
$pagebreak = false;
if ( $temp == '1' ) {
$pagebreak = true;
} else if ( strcasecmp($temp, 'true') == 0 ) {
$pagebreak = true;
}
}
// Determine text style for the index heading.
$styleH = '';
if (!empty($settings ['style_heading'])) {
$styleH = $settings ['style_heading'];
}
// Determine text styles per level.
// Syntax for a style level 1 is "styleL1="color:black;"".
// The default style is just 'color:black;'.
for ( $count = 0 ; $count < $max_outline_level ; $count++ ) {
$stylesL [$count + 1] = 'color:black;';
if (!empty($settings ['styleL'.($count + 1)])) {
$stylesL [$count + 1] = $settings ['styleL'.($count + 1)];
}
}
// Create Heading style if not empty.
// Default index heading style is taken from styles.xml
$title_style = $doc->getStyleName('contents heading');
if (!empty($styleH)) {
$properties = array();
$doc->getCSSStylePropertiesForODT ($properties, $styleH);
$properties ['style-parent'] = 'Heading';
$properties ['style-class'] = 'index';
$properties ['style-name'] = 'Contents_20_Heading_'.$indexNo;
$properties ['style-display-name'] = 'Contents Heading '.$indexNo;
$style_obj = ODTParagraphStyle::createParagraphStyle($properties);
$doc->addStyle($style_obj);
$title_style = $style_obj->getProperty('style-name');
}
// Create paragraph styles
$p_styles = array();
$p_styles_auto = array();
$indent = 0;
for ( $count = 0 ; $count < $max_outline_level ; $count++ )
{
$indent = $indents [$count];
$properties = array();
$doc->getCSSStylePropertiesForODT ($properties, $stylesL [$count+1]);
$properties ['style-parent'] = 'Index';
$properties ['style-class'] = 'index';
$properties ['style-position'] = $settings ['width'] - $indent .'cm';
$properties ['style-type'] = 'right';
$properties ['style-leader-style'] = 'dotted';
$properties ['style-leader-text'] = $leader_sign;
$properties ['margin-left'] = $indent.'cm';
$properties ['margin-right'] = '0cm';
$properties ['text-indent'] = '0cm';
$properties ['style-name'] = 'ToC '.$indexNo.'- Level '.($count+1);
$properties ['style-display-name'] = 'ToC '.$indexNo.', Level '.($count+1);
$style_obj = ODTParagraphStyle::createParagraphStyle($properties);
// Add paragraph style to common styles.
// (It MUST be added to styles NOT to automatic styles. Otherwise LibreOffice will
// overwrite/change the style on updating the TOC!!!)
$doc->addStyle($style_obj);
$p_styles [$count+1] = $style_obj->getProperty('style-name');
// Create a copy of that but with parent set to the copied style
// and no class
$properties ['style-parent'] = $style_obj->getProperty('style-name');
$properties ['style-class'] = NULL;
$properties ['style-name'] = 'ToC Auto '.$indexNo.'- Level '.($count+1);
$properties ['style-display-name'] = NULL;
$style_obj_auto = ODTParagraphStyle::createParagraphStyle($properties);
// Add paragraph style to automatic styles.
// (It MUST be added to automatic styles NOT to styles. Otherwise LibreOffice will
// overwrite/change the style on updating the TOC!!!)
$doc->addAutomaticStyle($style_obj_auto);
$p_styles_auto [$count+1] = $style_obj_auto->getProperty('style-name');
}
// Create text style for TOC text.
// (this MUST be a text style (not paragraph!) and MUST be placed in styles (not automatic styles) to work!)
for ( $count = 0 ; $count < $max_outline_level ; $count++ ) {
$properties = array();
$doc->getCSSStylePropertiesForODT ($properties, $stylesL [$count+1]);
$properties ['style-name'] = 'ToC '.$indexNo.'- Text Level '.($count+1);
$properties ['style-display-name'] = 'ToC '.$indexNo.', Level '.($count+1);
$style_obj = ODTTextStyle::createTextStyle($properties);
$stylesLNames [$count+1] = $style_obj->getProperty('style-name');
$doc->addStyle($style_obj);
}
// Generate ODT toc tag and content
switch ($type) {
case 'toc':
$tag = 'table-of-content';
$name = 'Table of Contents';
$index_name = 'Table of Contents';
$source_attrs = 'text:outline-level="'.$max_outline_level.'" text:use-index-marks="false"';
break;
case 'chapter':
$tag = 'table-of-content';
$name = 'Table of Contents';
$index_name = 'Table of Contents';
$source_attrs = 'text:outline-level="'.$max_outline_level.'" text:use-index-marks="false" text:index-scope="chapter"';
break;
}
$content = '';
$content .= '';
if (!empty($title)) {
$content .= ''.$title.'';
} else {
$content .= '';
}
// Create TOC templates per outline level.
// The styles listed here need to be the same as later used for the headers.
// Otherwise the style of the TOC entries/headers will change after an update.
for ( $count = 0 ; $count < $max_outline_level ; $count++ )
{
$level = $count + 1;
$content .= '';
$content .= '';
$content .= '';
if ($settings ['numbered_headings'] == true) {
$content .= ' ';
}
$content .= '';
$content .= '';
$content .= '';
$content .= '';
$content .= '';
}
$content .= '';
$content .= '';
if (!empty($title)) {
$content .= '';
$content .= ''.$title.'';
$content .= '';
}
// Add headers to TOC.
$page = 0;
$links = $settings ['create_links'];
if ($type == 'toc') {
$content .= self::getTOCBody ($toc, $p_styles_auto, $stylesLNames, $max_outline_level, $links);
} else {
$startRef = $settings ['start_ref'];
$content .= self::getChapterIndexBody ($toc, $p_styles_auto, $stylesLNames, $max_outline_level, $links, $startRef);
}
$content .= '';
$content .= '';
// Add a pagebreak if required.
if ( $pagebreak ) {
$style_name = $doc->createPagebreakStyle(NULL, false);
$content .= '';
}
// Return index content.
return $content;
}
/**
* This function creates the entries for a table of contents.
* All heading are included up to level $max_outline_level.
*
* @param array $p_styles Array of style names for the paragraphs.
* @param array $stylesLNames Array of style names for the links.
* @param array $max_outline_level Depth of the table of contents.
* @param boolean $links Shall links be created.
* @return string TOC body entries
*/
protected static function getTOCBody(array $toc, $p_styles, $stylesLNames, $max_outline_level, $links) {
$page = 0;
$content = '';
foreach ($toc as $item) {
$params = explode (',', $item);
// Only add the heading to the TOC if its <= $max_outline_level
if ( $params [3] <= $max_outline_level ) {
$level = $params [3];
$content .= '';
if ( $links == true ) {
$content .= '';
}
$content .= $params [2];
$content .= '';
$page++;
$content .= $page;
if ( $links == true ) {
$content .= '';
}
$content .= '';
}
}
return $content;
}
/**
* This function creates the entries for a chapter index.
* All headings of the chapter are included uo to level $max_outline_level.
*
* @param array $p_styles Array of style names for the paragraphs.
* @param array $stylesLNames Array of style names for the links.
* @param array $max_outline_level Depth of the table of contents.
* @param boolean $links Shall links be created.
* @param string $startRef Reference-ID of chapter main heading.
* @return string TOC body entries
*/
protected static function getChapterIndexBody(array $toc, $p_styles, $stylesLNames, $max_outline_level, $links, $startRef) {
$start_outline = 1;
$in_chapter = false;
$first = true;
$content = '';
foreach ($toc as $item) {
$params = explode (',', $item);
if ($in_chapter == true || $params [0] == $startRef ) {
$in_chapter = true;
// Is this the start of a new chapter?
if ( $first == false && $params [3] <= $start_outline ) {
break;
}
// Only add the heading to the TOC if its <= $max_outline_level
if ( $params [3] <= $max_outline_level ) {
$level = $params [3];
$content .= '';
if ( $links == true ) {
$content .= '';
}
$content .= $params [2];
$content .= '';
$page++;
$content .= $page;
if ( $links == true ) {
$content .= '';
}
$content .= '';
}
$first = false;
}
}
return $content;
}
}