2

Currently, in the EPUB version of the book I’m writing using LaTeX + TeX4ebook, the table of contents looks odd – it just contains the number and then the title of the chapter; nothing before the number; no period or colon after the number.

The current state

The chapters just have the number and then the title. Looks funky.

What I would like is for the format in both in-document table of contents (right) and the NCX table of contents (left) to follow the format Chapter n: Title for numbered chapters. That is to say, either of the following (preferably the former, but either works):

What I’m aiming for

It’s okay if “Chapter 1:” is part of the link.

Either way, numbered chapters should be prefixed with, for example, “Chapter 1:”.

In the PDF version I’ve solved this by redefining \addchaptertocentry in terms of \chapapp, but this appears not to affect TeX4ht ⁠/ TeX4ebook. I’ve dug into the TeX4ebook and TeX4ht sources, but they’re complex enough that I haven’t been able to figure out what it uses to fill that title – I’ve figured out that \ConfigureToc is used to set the HTML ⁠/ XML around the number and title, but I haven’t figured out how to change what actually goes inside. Besides, I want it to work for both the NCX and in-document tables.

How do I change the format of the NCX and in-document table of contents lines to include a prefix and a suffix for the number?


Worth mentioning is that I’m using TeX4ht’s \TableOfContents in place of the LaTeX \tableofcontents for customizability’s sake. Here’s an MWE to play with, compiled with tex4ebook -l -B build/ -f epub3 -c xhtml.cfg test.tex – using a build directory is actually important, since for some reason without it the NCX isn’t inserted properly. (Code for making the formatting happen in the PDF version is omitted here in the interest of brevity – so don’t worry if the PDF version ends up looking wrong.)

test.tex
\documentclass{scrbook}

% Add something here?

\begin{document}

\tableofcontents

\chapter*{Introduction}
\section{Prologue} % This shouldn’t be prefixed with “Chapter”.
\chapter{The Machine}

\end{document}
xhtml.cfg
\Preamble{xhtml}

% Replace LaTeX’s `\tableofcontents` (which doesn’t record `\chapter*`s)
% with TeX4Ht’s automatic `\TableOfContents` (which can).
\renewcommand\tableofcontents{%
    \TableOfContents[part,likepart,chapter,likechapter,section,likesection,subsection,likesubsection]%
}

\Configure{tableofcontents}
    {\IgnorePar\EndP\HCode{<h2 class="chapter-title">\contentsname</h2><nav class="table-of-contents">}\IgnorePar} % Before ToC.
    {} % End of ToC.
    {\IgnorePar\HCode{</nav>}\ShowPar} % After ToC.
    {\newline} % Before non-indented \par.
    {\newline} % Before indented \par.

% Add something here?

\begin{document}
\EndPreamble
1
  • Just a note: KOMA-Script classes provide \addchap for not numbered chapters with automatic ToC entry. It also provides commands, that allow to modify the ToC, e.g. prepend ”Chapter“ to the number of the chapter entries. But I don't know whether or not tex4ht supports these modification. Commented Jul 29 at 7:06

2 Answers 2

1

The formatting of Epub contents is configured using \Configure{NavSection}. This configuration file should work:

\Preamble{xhtml}

\catcode`\:=11
\def\:chaptertitle{chapter}
\Configure{NavSection}{%
    \booltrue{tocnoempty}
    \HCode{<li>}\ifx\curr:sect:type\:chaptertitle Chapter\space\fi}{\HCode{<ol>\Hnewline}}{\ }{\Tg</ol>\Tg</li>}
\catcode`\:=12
\begin{document}
\EndPreamble

I've used the code from tex4ebook-epub3.4ht, and added this test: \ifx\curr:sect:type\:chaptertitle Chapter\space\fi. The \curr:sect:type command is declared by TeX4ebook and holds the current section type. We can use that for test if the current TOC entry is a chapter.

To get the word chapter to the NCX, file, you can use this build file:

local filter = require "make4ht-filter"

local process = filter {
  function(text)
    local text = text:gsub('<navmark type="chapter">', '<navmark type="chapter">Chapter ')
    print(text)
    return text
  end
}

Make:match("ncx$", process)

The resulting Epub looks like this:

resulting epub TOC

3
  • Hmm, this appears not to do anything at all for me when using the code in xhtml.cfg in the question (the \Configure{tableofcontents} appears to be the culprit; also breaks the NCX ToC)… I’d also like not to have any number on unnumbered chapters (like the prologue there; that should just be Prologue), and a colon after the chapter number (Chapter 1: The Machine) – is this possible? Commented Aug 16 at 9:05
  • (Actually, I can’t get the NCX ToC to include the numbers or the word “Chapter” at all, even with your exact example. I’m on TeX4ebook v0.4b and TeX4ht 2023-10-13-15:32 – MiKTeX’s [and thus CTAN’s?] TeX4ht might be too old?) Commented Aug 16 at 9:37
  • @obskyr I've edited my answer with a build file that will add Chapter to the NCX file. But the reason why the contents is missing is mainly caused by the \Configure{tableofconents} in the .cfg file. It overrides the structure needed in Epub 3. Maybe we used this configuration when you were producing Epub 2? I don't remember it clearly. Commented Aug 16 at 19:37
0

With Michal’s hints, I’ve arrived at the following (overengineered-feeling) solution. It satisfies the following requirements:

  • Chapters follow the format Chapter 1: Chapter Title in the table of contents inside the document.
    • Everything is part of the <a> link instead of Chapter 1: being outside, as would normally be the case with TeX4ht.
  • Chapters follow the format Chapter 1: Chapter Title in the table of contents shown in the e-reader’s user interface.
  • In addition, it lets you change the types of divisions that should be included in the table of contents in one place, and applies that everywhere.

It works by changing these things:

  • Use TeX4ht’s \TableOfContents in place of the default \tableofcontents.
  • \Configure{tableofcontents} to include e.g. likechapter.
  • Use \Configure{NavSection} and \peek_regex_replace_once to capture the division number.
  • Add Chapter , the captured division number, and : to the in-document table of contents using \Configure{TocLink}. (This regex solution is highly hacky – let me know if anyone knows of a better way to move the number into the <a> link!)
  • Add Chapter and : to the NCX table of contents with a deferred \Configure{NavSection}.

It works!

xhtml.cfg

\Preamble{xhtml}

% Edit this to change what the table of contents should record.
% (Doesn’t support KOMA-Script’s `\addchap` – this could probably be
% implemented, but let’s not unless someone needs it.)
\def\tableofcontentsincludes{part,likepart,appendix,chapter,likechapter,section,likesection}


% Replace LaTeX’s `\tableofcontents` (which doesn’t record `\chapter*`s)
% with TeX4Ht’s automatic `\TableOfContents` (which can).
\ExplSyntaxOn
\RenewDocumentCommand{\tableofcontents}{}{%
    % https://tex.stackexchange.com/a/26489/392788
    \exp_args:NNV \TableOfContents[\tableofcontentsincludes]%
}
\ExplSyntaxOff


% What we want is for the table of contents to say “Chapter 1: Chapter Title”
% instead of simply “1 Chapter Title”. The way EPUB 3 works, it has two tables
% of contents for the document: One in the document (X)HTML, and one in the
% NCX file. It also has two different places to *display* the table of contents
% for the document: Inside the actual book, and in the user interface.
% The table of contents inside the actual book is, of course, the one in the
% document (X)HTML. Testing, however, reveals that the user interface ToC comes
% from one of two sources: either from the NCX file, *or* from the document
% (X)HTML *if it has the attribute `epub:type="toc"`. (This might vary from
% e-reader to e-reader.) To that end, if we want “Chapter 1: Chapter Title”,
% we should make sure that it says so both in the document (X)HTML and the NCX
% file.

\catcode`\:=11

% Here we add a custom heading.
\ExplSyntaxOn
\Configure{NavMap}
    {% Before the table of contents.
        \ifvmode\IgnorePar\fi\EndP%
        \boolfalse{tocnoempty}%
        \global\advance\:toccount by1%
        \HCode{<nav\space id="toc\the\:toccount"\space class="toc"\ifnum\:toccount<2 \space epub:type="toc"\space role="doc-toc"\fi>\Hnewline}%
        % Comment the above line and uncomment the line below to use the NCX
        % table of contents in the user interface.
        % \HCode{<nav\space id="toc\the\:toccount"\space class="toc">\Hnewline<ol>}%
        % Custom heading for the table of contents.
        \HCode{<div\space class="heading\space chapter-heading\space without-number"><h2\space class="chapter-title">}\contentsname\HCode{</h2></div>\Hnewline}%
        \HCode{<ol>}%
        \opf:registerfilename{\FileName}%
        \ifnum\:toccount<2 \opf:add:property{nav}\fi%
    }
    {% At the end of the table of contents.
        \exp_args:Ne \usetoclevels{\tableofcontentsincludes}%
        \ifbool{tocnoempty}{}{\HCode{<li><a href="\jobname.\:html">Document</a></li>}}%
        \HCode{</ol></nav>}%
    }
\ExplSyntaxOff

% Here, we configure the table of contents to treat `likechapter` (i.e.
% `\chapter*{…}` like it does `chapter` (i.e. `\chapter{…}`). At the time of
% writing, TeX4ebook does not do this by default.
\ExplSyntaxOn
\seq_new:N \tableofcontentsincludes_seq
\seq_new:N \cur_potential_divisions_to_close_seq
\seq_new:N \cur_divisions_to_close_seq
\seq_set_split:NnV \tableofcontentsincludes_seq {,}{\tableofcontentsincludes}
\Configure{tableofcontents}
    {% Before ToC.
        \a:NavMap%
        %
        \resettoclevels{part,likepart,appendix,chapter,likechapter,section,likesection,subsection,likesubsection,subsubsection,likesubsubsection}%
        %
        % We have to configure each division we want using `\navsection` (see
        % `tex4ebook-epub3.4ht` in the TeX4ebook source).' Since we’ve made the
        % divisions variable, we have to generate these dynamically.
        \tl_new:N \null_tl% Throwaway variable.
        \seq_set_eq:NN \cur_potential_divisions_to_close_seq \tableofcontentsincludes_seq%
        \seq_set_eq:NN \cur_divisions_to_close_seq \tableofcontentsincludes_seq%
        \seq_map_inline:Nn \tableofcontentsincludes_seq {%
            % A little niggle is that, for example, `\navsection{likechapter}` should
            % include `chapter`, i.e. `\navsection{likechapter}{chapter, likechapter, …}`.
            % Thus, we only update the running list of sections to close when
            % we encounter a non-`like` division.
            \tl_if_regex_match:nnF {##1}{^like}{\seq_set_eq:NN \cur_divisions_to_close_seq \cur_potential_divisions_to_close_seq}%
            \exp_args:Nne \navsection
                {##1}
                {\seq_use:Nn \cur_divisions_to_close_seq {,}}%
            \seq_gpop:NN \cur_potential_divisions_to_close_seq \null_tl%
        }%
        %
        \Configure{toTocLink}{}{}%
    }
    {\b:NavMap} % End of ToC.
    {} % After ToC.
    {} % Before non-indented \par.
    {} % Before indented \par.
\ExplSyntaxOff

% We’ll need these for turning “1 Chapter Title” into “Chapter 1: Chapter
% Title”.
\ExplSyntaxOn
\NewDocumentCommand{\curr:sect:prefix}{}{%
    \str_case_e:nnT{\curr:sect:type}{%
        {part}{Part}
        {chapter}{\chaptername}
    }{\space}%
}

\NewDocumentCommand{\curr:sect:colon}{}{%
    \str_case_e:nnT{\curr:sect:type}{%
        {part}{:}
        {chapter}{:}
        {section}{:}
        {subsection}{:}
        {subsubsection}{:}
    }{\space}%
}
\ExplSyntaxOff

% We want the label `Chapter 1:` to be part of the `<a>` link, not outside
% as it is by default.
\NewDocumentCommand{\curr:sect:number}{}{}
\Configure{TocLink}{%
    \Link{#2}{#3}%
    \curr:sect:prefix\curr:sect:number\curr:sect:colon #4%
    \EndLink%
}

% This is a bit of a funky workaround: We’re capturing the division number
% using regex below. In order to do this, we need a single csname to call.
\NewDocumentCommand{\curr:sect:number:set}{m}{%
    \RenewDocumentCommand{\curr:sect:number}{}{#1}%
}

% Here, we change “1 Chapter Title” to “Chapter 1: Chapter Title” in the
% in-document (X)HTML table of contents.
\ExplSyntaxOn
\Configure{NavSection}
    {% Before the division number.
        \booltrue{tocnoempty}%
        \HCode{<li>}%
        \peek_regex_replace_once:nnF{([^\d.]?[\d.]+)}
            {\c{curr:sect:number:set}\{\0\}}
            {\RenewDocumentCommand{\curr:sect:number}{}{}}%
    }
    {\HCode{<ol>\Hnewline}} % Between the division title and its children.
    {} % In between division number and division title.
    {\HCode{</ol></li>}} % After the division’s children.
\ExplSyntaxOff

% Here, we turn “1 Chapter Title” into “Chapter 1: Chapter Title” in the NCX
% table of contents. Truly an ugly hack among ugly hacks, but it works!
% We have to `\Configure{NavSection}` at the correct point in `tex4ebook.4ht`,
% because if we do it now, it’ll just get overwritten.
\makeatletter
\ExplSyntaxOn
\NewCommandCopy{\ncx:head@original}{\ncx:head}
\NewCommandCopy{\TableOfContents@original}{\TableOfContents}
\RenewDocumentCommand{\ncx:head}{}{%
    \ncx:head@original%
    %
    \Configure{NavSection}
        {%
            \booltrue{tocnoempty}%
            \HCode{\Hnewline<navPoint\space id="navPoint-}%
            \stepnavpoint%
            \HCode{"\space playOrder="}\the\navpoint%
            \HCode{">\Hnewline}%
            \HCode{<navLabel>\Hnewline<text><navmark\space type="\curr:sect:type">}%
            %
            \curr:sect:prefix%
        }
        {%
            \HCode{</text>\Hnewline</navLabel>\Hnewline}%
            \HCode{<content\space src="\navmapsrc"\space />}%
        }
        {%
            \HCode{</navmark>}%
            \curr:sect:colon%
        }
        {\HCode{</navPoint>\Hnewline}}%
    %
    \RenewDocumentCommand{\TableOfContents}{o}{%
        \exp_args:NNV \TableOfContents@original[\tableofcontentsincludes]%
        \RenewCommandCopy{\TableOfContents}{\TableOfContents@original}%
    }%
}
\ExplSyntaxOff
\makeatother

\catcode`:=12

\begin{document}
\EndPreamble

test.tex

\documentclass{scrbook}

% Everything here in the preamble is only required for the PDF version.

% \iftexforht{[if true…]}{[if false…]}:
% Detect whether you’re running in `tex4ebook` (or similar) or not.
% Some typographical decisions may need to differ between a PDF and an EPUB
% edition. For example, to insert HTML, you may do:
% \iftexforht{\HCode{<cite>}The Time Machine\HCode{</cite>}}{\textit{The Time Machine}}
\makeatletter
\ifdefined\HCode
   \let\iftexforht\@firstoftwo
\else
   \let\iftexforht\@secondoftwo
\fi
\makeatother

% This lets us have `\chapter*` add to the table of contents in the PDF
% version. (This is handled separately for TeX4ht.)
\makeatletter
\NewCommandCopy{\chapter@original}{\chapter}
\RenewDocumentCommand{\chapter}{sm}{%
    \IfBooleanTF{#1}{%
        \chapter@original*{#2}%
        \markboth{#2}{#2}%
        % We have TeX4ht set up to add `\chapter*`s to the table of contents
        % without using `\addcontentsline`. Using it would create a duplicate
        % entry in the table of contents.
        \iftexforht{}{\addcontentsline{toc}{chapter}{#2}}%
    }{%
        \chapter@original{#2}%
    }%
}

\NewCommandCopy{\tableofcontents@original}{\tableofcontents}
\RenewDocumentCommand{\tableofcontents}{}{%
    \iftexforht{%
        \tableofcontents@original%
    }{
        {%
            % This is required because `\tableofcontents` internally calls
            % `\chapter*`, meaning it’ll add itself to the table of contents
            % if we use our redefined version.
            \let\chapter\chapter@original%
            \tableofcontents@original%
        }%
    }
}
\makeatother


\begin{document}

\tableofcontents

\chapter*{Introduction}
\section{Prologue} % This shouldn’t be prefixed with “Chapter”.
\chapter{The Machine}

\end{document}

It’s a complex solution, for sure – I feel like there perhaps should be a more central way to set this format – but from my testing, it works as it should.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.