Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

(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:

  1. 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...?).
  2. It's ugly, I'd much rather have a redefinition of the standard \chapter and \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!

share|improve this question
    
Do you think you could turn your code into a complete MWE? It really helps people recreate the problem you're describing! –  cmhughes Oct 25 '11 at 3:30
    
This is actually a very good exercise: whilst trying to make the MWE compile I found out a dependency on fixltx2e I totally missed (it's one of the packages on my "always include" list). –  mpr Oct 25 '11 at 4:16
    
The dependency on fixltx2e can be eliminated by using \protect\raisebox –  egreg Oct 25 '11 at 10:31
add comment

2 Answers 2

up vote 2 down vote accepted
\documentclass{book}
\usepackage{xparse}
\usepackage[colorlinks,linktocpage]{hyperref}
\usepackage{bookmark}
\usepackage{hypbmsec}

\newcounter{tocBackrefCount}

\makeatletter
\def\MPR@chapter{\@ifstar{\HYPBMSEC@chapter*}\MPR@chapter@}

\DeclareDocumentCommand{\MPR@chapter@}{d() o m}{
  \stepcounter{tocBackrefCount}
  \IfNoValueTF{#1}
    {\IfNoValueTF{#2}
      {\HYPBMSEC@chapter(#3)[\mpr@opt{#3}]{\mpr@mand{#3}}}
      {\HYPBMSEC@chapter(#2)[\mpr@opt{#2}]{\mpr@mand{#3}}}
    }
    {\IfNoValueTF{#2}
      {\HYPBMSEC@chapter(#1)[\mpr@opt{#3}]{\mpr@mand{#3}}}
      {\HYPBMSEC@chapter(#1)[\mpr@opt{#2}]{\mpr@mand{#3}}}
    }
}
\def\mpr@opt#1{\protect\raisebox{\baselineskip}{%
  \protect\hypertarget{toc:backref:\thetocBackrefCount}{}}#1}
\def\mpr@mand#1{\hyperlink{toc:backref:\thetocBackrefCount}{#1}}

\AtBeginDocument{
  \let\HYPBMSEC@chapter\chapter
  \let\chapter\MPR@chapter
}
\makeatother

\begin{document}
  \tableofcontents

  \chapter{No optional argument}
    \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}

Loading bookmark usually saves the number of LaTeX runs.

Generic definitions

Here is how one can extend the previous method to redefine all desired sectional commands

\documentclass{book}
\usepackage{xparse,etoolbox}
\usepackage[colorlinks,linktocpage]{hyperref}
\usepackage{bookmark}
\usepackage{hypbmsec}

\makeatletter

\newcounter{tocBackrefCount}

\def\MPR@command#1{%
  \AtBeginDocument{\csletcs{HYPBMSEC@#1}{#1}\csletcs{#1}{MPR@#1}}%
  \@namedef{MPR@#1}{\@ifstar{\@nameuse{HYPBMSEC@#1}*}{\@nameuse{MPR@#1@}}}%
  % define \MPR@<command>@
  \expandafter\DeclareDocumentCommand\csname MPR@#1@\endcsname{d() o m}{
    \stepcounter{tocBackrefCount}
    \IfNoValueTF{##1}
      {\IfNoValueTF{##2}
        {\@nameuse{HYPBMSEC@#1}(##3)[\mpr@opt{##3}]{\mpr@mand{##3}}}
        {\@nameuse{HYPBMSEC@#1}(##2)[\mpr@opt{##2}]{\mpr@mand{##3}}}
      }
      {\IfNoValueTF{##2}
        {\@nameuse{HYPBMSEC@#1}(##1)[\mpr@opt{##3}]{\mpr@mand{##3}}}
        {\@nameuse{HYPBMSEC@#1}(##1)[\mpr@opt{##2}]{\mpr@mand{##3}}}
      }
  }
}
\def\mpr@opt#1{\protect\raisebox{\baselineskip}{%
  \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

\end{document}

Now one has only to list what commands to redefine, in this example only \chapter and \section, via \MPR@command{<section level>}.

I've not succeeded in redefining conveniently \chapter* and similar to allow for optional arguments. Still thinking about it.

share|improve this answer
    
Sorry it took me this long to respond. Your MWE works like a charm btw. Two requests though. Firstly, I can't seem to get the code to generalize to sections, etc. all the way down to subparagraphs... would you care to provide further examples? Secondly, I usually use \chapter* followed by \phantomsection and \addcontentsline to get unnumbered sections which do appear in the ToC (and should thus be linked), is there any way to modify your \chapter* definition above to achieve this? (and define, for instance, \chapter** to behave like a "normal" \chapter*)? –  mpr Oct 29 '11 at 2:33
    
This is GREAT! Thanks a million! Please do let me know if you can come up with a solution for the starred commands. I (unelegantly) "solved" this issue by inserting \addcontentsline commands... don't know if it helps though. PS: I'll mark this question answered nevertheless, you've given me much code to ponder about :) –  mpr Oct 29 '11 at 22:01
    
I think I managed to accomplish a "working" solution which is not excessively horrid, alas I can't post code snippets here (and I'm not gonna make further noise by presenting my own, possibly wrong, answers as I've done this far)... anyway, I get lots of "innocent" destination with the same identifier... warnings... If you find a way I can post this piece of code without adding further confusion let me know please :) –  mpr Oct 31 '11 at 2:04
add comment

Here is the usual pattern to wrap some command into another one. For the chapter example:

\let\chapterOriginal\chapter
\renewcommand{\chapter}{...\chapterOriginal ...}

The "let" creates another name for the original command, which is still valid, when the original command is redefined.

share|improve this answer
    
I thought about that, then I read this entry on the TeX UK FAQ and got squeamish... is it safe to use the \let method for \chapter? (seeing as it takes optional arguments) –  mpr Oct 25 '11 at 11:43
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.