(Somewhat related to Defining a Command for Linked and Indexed Section Headings).
I'm trying to have the section headings link to their entry in the Table of Contents so as to get "two-way" navigation, eg: a user looks in the Table of Contents for a section title, jumps there, reads a couple of lines, clicks on the section title again and gets taken to the section's entry in the Table of Contents once more.
My original question is here, from the discussion there I got the following code:
\newcounter{tocBackrefCount}
\newcommand{\Chapter}[3]{%
\chapter%
(#1)%
[\protect\raisebox{\baselineskip}{\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#2]%
{\hyperlink{toc:backref:\thetocBackrefCount}{#3}}\stepcounter{tocBackrefCount}%
}
(nb: the parenthesis argument for \chapter are a courtesy of the hypbmsec package) this macro is called like so \Chapter{bookmark}{short}{long}, where bookmark is the bookmark name as you wish it to appear in the viewer, short is the ToC entry, and long is the actual section title (in text, the one which will be linked).
I currently face three problems with this approach:
- It takes between 3 to 5 compilation runs to get all the references in place (maybe the hypdestopt package has something to do with it...?).
- It's ugly, I'd much rather have a redefinition of the standard
\chapterand\chapter*commands, or at least make it take optional arguments which default like the standard ones.
Care to share your TeXpertise on the matter?
PS: the \raisebox command is there to avoid hyperref setting the target's anchor to the lower-left corner of the ToC entry (try it without it and you'll see what I mean).
PPS: here's a MWE for your viewing pleasure:
\documentclass{book}
\usepackage[colorlinks,linktocpage]{hyperref}
\usepackage{hypbmsec}
\newcounter{tocBackrefCount}
\newcommand{\Chapter}[3]{%
\chapter(#1)%
[\protect\raisebox{\baselineskip}{\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#2]%
{\hyperlink{toc:backref:\thetocBackrefCount}{#3}}%
\stepcounter{tocBackrefCount}}
\begin{document}
\tableofcontents
\Chapter{Bookmark 1}{Short 1}{Long 1}
\noindent\ldots
\Chapter{Bookmark 2}{Short 2}{Long 2}
\noindent\ldots
\Chapter{Bookmark 3}{Short 3}{Long 3}
\noindent\ldots
\Chapter{Bookmark 4}{Short 4}{Long 4}
\noindent\ldots
\Chapter{Bookmark 5}{Short 5}{Long 5}
\noindent\ldots
\Chapter{Bookmark 6}{Short 6}{Long 6}
\noindent\ldots
\Chapter{Bookmark 7}{Short 7}{Long 7}
\noindent\ldots
\end{document}
Possible Nice Solution
Fiddling around with this for the best part of the weekend I got the following "final" version of @egreg's code:
\documentclass{book}
\usepackage{xparse}
\usepackage{etoolbox}
\usepackage[colorlinks,linktocpage,plainpages=false,pdfpagelabels]{hyperref}
\usepackage{bookmark}
\usepackage{hypbmsec}
\usepackage{hypdestopt}
\makeatletter
\newcounter{tocBackrefCount}
\def\MPR@command#1{%
\AtBeginDocument{\csletcs{HYPBMSEC@#1}{#1}\csletcs{#1}{MPR@#1}}%
\expandafter\DeclareDocumentCommand\csname MPR@#1\endcsname{s d() o m}{
\stepcounter{tocBackrefCount}
\IfBooleanTF{##1}
{\IfNoValueTF{##2}
{\IfNoValueTF{##3}
{\addtocounter{tocBackrefCount}{-1}\@nameuse{HYPBMSEC@#1}*{##4}}
{\@nameuse{HYPBMSEC@#1}*{\phantomsection{}\mpr@mand{##4}%
\addcontentsline{toc}{#1}{\texorpdfstring{\mpr@opt{##3}}{##3}}}}
}
{\IfNoValueTF{##3}
{\@nameuse{HYPBMSEC@#1}*{\phantomsection{}\mpr@mand{##4}%
\addcontentsline{toc}{#1}{\texorpdfstring{\mpr@opt{##4}}{##2}}}}
{\@nameuse{HYPBMSEC@#1}*{\phantomsection{}\mpr@mand{##4}%
\addcontentsline{toc}{#1}{\texorpdfstring{\mpr@opt{##3}}{##2}}}}
}
}
{\IfNoValueTF{##2}
{\IfNoValueTF{##3}
{\@nameuse{HYPBMSEC@#1}(##4)[\mpr@opt{##4}]{\mpr@mand{##4}}}
{\@nameuse{HYPBMSEC@#1}(##3)[\mpr@opt{##3}]{\mpr@mand{##4}}}
}
{\IfNoValueTF{##3}
{\@nameuse{HYPBMSEC@#1}(##2)[\mpr@opt{##4}]{\mpr@mand{##4}}}
{\@nameuse{HYPBMSEC@#1}(##2)[\mpr@opt{##3}]{\mpr@mand{##4}}}
}
}
}
}
\def\mpr@opt#1{\protect\raisebox{1.6ex}{%
\protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#1}
\def\mpr@mand#1{\hyperlink{toc:backref:\thetocBackrefCount}{#1}}
\MPR@command{chapter}
\MPR@command{section}
\makeatother
\begin{document}
\tableofcontents
\chapter{No optional argument}
\noindent\ldots
\section{ABC}
\noindent\ldots
\chapter[opt]{Optional argument}
\noindent\ldots
\chapter(book){No optional argument + bookmark}
\noindent\ldots
\chapter(book)[opt]{Both optional arguments}
\noindent\ldots
\chapter*{No optional argument}
\noindent\ldots
\section*{ABC}
\noindent\ldots
\chapter*[opt]{Optional argument}
\noindent\ldots
\chapter*(book){No optional argument + bookmark}
\noindent\ldots
\chapter*(book)[opt]{Both optional arguments}
\noindent\ldots
\end{document}
This deals gracefully with starred versions of the sectioning commands. Note the addition of the hypdestopt package: without it you'd get spurious warnings about duplicated hyperref targets.
Note that we no longer \reisebox by a whole \bsaelineskip: that produces certain undesired artifacts in the ToC; instead, the empirically sound value of 1.6ex is used. I wager this will not be a sure shot solution and am open to suggestions on this matter.
This solution works the best for me, but I'd like to hear your ideas as well, I'm sure there's more to be said on the matter!
\protect\raisebox– egreg Oct 25 '11 at 10:31