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.

In bidi package, we have three footnote commands \footnote (typesetting RTL footnotes in RTL mode and typesetting LTR footnotes in LTR modes), \RTLfootnote (always typeset RTL footnote), and \LTRfootnote (always typeset LTR footnotes). Currently bidi package has a complicated way to detect what is the first footnote command in a page and it failed when footnotes are split.

Hence my question is that is it possible (with using zref bundle) to detect what is the first footnote command used in a page and accordingly (if the first footnote in a page is RTL, put the footnote rule to be on the right hand side and if the first footnote in a page is LTR, put the footnote rule on the left hand side), change the behaviour of footnote rule.

Here is an example which seems to work correctly:

\documentclass{article}
\usepackage{zref-perpage}
\usepackage{bidi}
\makeatletter
\@definecounter{bidifootnote}

\zmakeperpage{bidifootnote}
\long\def\@RTLfootnotetext#1{\insert\footins{%
    \stepcounter{bidifootnote}\@RTLtrue
    \ifnum\c@bidifootnote=1\if@RTL\global\let\footnoterule\right@footnote\else\global\let\footnoterule\left@footnote\fi\fi
    \reset@font\footnotesize
    \interlinepenalty\interfootnotelinepenalty
    \splittopskip\footnotesep
    \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
    \hsize\columnwidth \@parboxrestore
    \protected@edef\@currentlabel{%
       \csname p@footnote\endcsname\@thefnmark
    }%
    \color@begingroup
      \@makefntext{%
        \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
    \color@endgroup}}%


\long\def\@LTRfootnotetext#1{\insert\footins{\stepcounter{bidifootnote}\@RTLfalse%
    \ifnum\c@bidifootnote=1\if@RTL\global\let\footnoterule\right@footnote\else\global\let\footnoterule\left@footnote\fi\fi
    \reset@font\footnotesize
    \interlinepenalty\interfootnotelinepenalty
    \splittopskip\footnotesep
    \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
    \hsize\columnwidth \@parboxrestore
    \protected@edef\@currentlabel{%
       \csname p@footnote\endcsname\@thefnmark
    }%
    \color@begingroup
      \@makefntext{%
        \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
    \color@endgroup}}%



\long\def\@footnotetext#1{\insert\footins{%
    \stepcounter{bidifootnote}\if@RTL@footnote\@RTLtrue\else\@RTLfalse\fi
    \ifnum\c@bidifootnote=1\if@RTL\global\let\footnoterule\right@footnote\else\global\let\footnoterule\left@footnote\fi\fi
    \reset@font\footnotesize
    \interlinepenalty\interfootnotelinepenalty
    \splittopskip\footnotesep
    \splitmaxdepth \dp\strutbox \floatingpenalty \@MM
    \hsize\columnwidth \@parboxrestore
    \protected@edef\@currentlabel{%
       \csname p@footnote\endcsname\@thefnmark
    }%
    \color@begingroup
      \@makefntext{%
        \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}%
    \color@endgroup}}%
\makeatother
\begin{document}
\RTLfootnote{This is a test.}\LTRfootnote{This is a test.}
\newpage
\LTRfootnotetext[3]{This is a test.}\RTLfootnote[4]{This is a footnote.}
\end{document}
share|improve this question
add comment

2 Answers

up vote 6 down vote accepted
+50

The following solutions uses labels to know the page, where a footnote command is executed. The first executed footnote (\@LTRfootnotetext or \@RTLfootnotetext) globally defines the macro \footdir@<absolute page number> with L/R for the rule left or right. \footnoterule checks that macro to print the right rule.

\documentclass{article}
\usepackage{zref-abspage}[2010/03/26]
\usepackage{auxhook}
\usepackage{ltxcmds}[2010/11/12]
\usepackage{bidi}

\makeatletter
\newcounter{footdir@label}
\renewcommand*{\thefootdir@label}{footdir@\the\value{footdir@label}}
\newcommand*{\footdir@write}{%
  \stepcounter{footdir@label}%
  \zref@labelbyprops{\thefootdir@label}{abspage}%
}
\newif\iffootdir@debug
\footdir@debugtrue
\newcommand*{\footdir@debug}[1]{%
  \iffootdir@debug
    \typeout{[footdir] #1}%
  \fi
}
\@ifpackagelater{zref-abspage}{2012/10/27}{%
  % this version is not yet released
  \newcommand*{\footdir@LeftRightElse}{%
    \ltx@ifundefined{footdir@\the\value{zabspage}}{%
      \footdir@debug{abspage \the\value{zabspage}: else}%
      \ltx@thirdofthree
    }{%
      \if\csname footdir@\the\value{zabspage}\endcsname L%
        \footdir@debug{abspage \the\value{zabspage}: left}%
        \expandafter\ltx@firstofthree
      \else
        \footdir@debug{abspage \the\value{zabspage}: right}%
        \expandafter\ltx@secondofthree
      \fi
    }%
  }%
}{%
  \providecommand*{\c@zabspage}{\c@abspage}%
  \newcommand*{\footdir@LeftRightElse}{%
    \footdir@write
    \zifrefundefined{\thefootdir@label}{%
      \footdir@debug{abspage ??: else}%  
      \ltx@thirdofthree
    }{%
      \edef\footdir@abspage{%
        \zref@extractdefault{\thefootdir@label}{abspage}{0}%
      }%
      \ltx@ifundefined{footdir@\footdir@abspage}{%
        \footdir@debug{\footdir@abspage: else}%   
        \ltx@thirdofthree
      }{%
        \if\csname footdir@\footdir@abspage\endcsname L%
          \footdir@debug{\footdir@abspage: left}%
          \expandafter\ltx@firstofthree
        \else
          \footdir@debug{\footdir@abspage: right}%
          \expandafter\ltx@secondofthree
        \fi
      }%   
    }%     
  }%       
}          
\newcommand*{\footdir@fntext}[1]{%
  \footdir@write
  \zifrefundefined{\thefootdir@label}{%
  }{%
    \edef\footdir@name{%
      footdir@\zref@extractdefault{\thefootdir@label}{abspage}{0}%
    }%
    \@ifundefined{\footdir@name}{%
      \expandafter\gdef\csname\footdir@name\endcsname{#1}%
    }{}%
  }%
}   
\@ifdefinable{\footdir@ORG@RTLfootnotetext}{%
  \let\footdir@ORG@RTLfootnotetext\@RTLfootnotetext
  \def\@RTLfootnotetext{%
    \footdir@fntext{R}%  
    \footdir@ORG@RTLfootnotetext
  }%
}   
\@ifdefinable{\footdir@ORG@LTRfootnotetext}{%
  \let\footdir@ORG@LTRfootnotetext\@LTRfootnotetext
  \def\@LTRfootnotetext{%
    \footdir@fntext{L}%  
    \footdir@ORG@LTRfootnotetext
  }%
}   
\def\footnoterule{%
  \footdir@LeftRightElse
    \left@footnoterule  
    \right@footnoterule 
    \left@footnoterule  
}
\makeatother

\begin{document}
\RTLfootnote{This is a test.}\LTRfootnote{This is a test.}
\newpage
\LTRfootnotetext[3]{This is a test.}\RTLfootnote[4]{This is a footnote.}
\newpage
\beginR 
\RTLfootnote{This is a test.}\LTRfootnote{This is a test.}
\endR
\newpage
\beginR 
\LTRfootnotetext[3]{This is a test.}\RTLfootnote[4]{This is a footnote.}
\endR
\end{document}

The debug output:

[footdir] abspage 1: right
[1]
[footdir] abspage 2: left
[2]
[footdir] abspage 3: right
[3]
[footdir] abspage 4: left
[4]

Extension for footnotes, split over two pages

\documentclass{article}
\usepackage{lipsum}
\usepackage{zref-abspage}[2010/03/26]
\usepackage{auxhook}
\usepackage{ltxcmds}[2010/11/12]
\usepackage{bidi}

\makeatletter
\newcounter{footdir@label}
\renewcommand*{\thefootdir@label}{footdir@\the\value{footdir@label}}
\newcommand*{\footdir@write}{%
  \stepcounter{footdir@label}%
  \zref@labelbyprops{\thefootdir@label}{abspage}%
}
\newif\iffootdir@debug
\footdir@debugtrue
\newtoks\footdir@toks
\newcommand*{\footdir@debug}[1]{%
  \iffootdir@debug
    \typeout{[footdir] #1}%
  \fi
}
\@ifpackagelater{zref-abspage}{2012/10/27}{%
  \newcommand*{\footdir@LeftRightElse}{%
    \ltx@ifundefined{footdir@\the\value{zabspage}}{%
      \footdir@debug{abspage \the\value{zabspage}: else}%
      \ltx@thirdofthree
    }{%
      \if\csname footdir@\the\value{zabspage}\endcsname L%
        \footdir@debug{abspage \the\value{zabspage}: left}%
        \expandafter\ltx@firstofthree
      \else
        \footdir@debug{abspage \the\value{zabspage}: right}%
        \expandafter\ltx@secondofthree
      \fi
    }%
  }%
}{%
  \providecommand*{\c@zabspage}{\c@abspage}%
  \newcommand*{\footdir@LeftRightElse}{%
    \footdir@write
    \zifrefundefined{\thefootdir@label}{%
      \footdir@debug{abspage ??: else}%  
      \ltx@thirdofthree
    }{%
      \edef\footdir@abspage{%
        \zref@extractdefault{\thefootdir@label}{abspage}{0}%
      }%
      \ltx@ifundefined{footdir@\footdir@abspage}{%
        \footdir@debug{\footdir@abspage: else}%   
        \ltx@thirdofthree
      }{%
        \if\csname footdir@\footdir@abspage\endcsname L%
          \footdir@debug{\footdir@abspage: left}%
          \expandafter\ltx@firstofthree
        \else
          \footdir@debug{\footdir@abspage: right}%
          \expandafter\ltx@secondofthree
        \fi
      }%   
    }%     
  }%       
}          
\newcommand*{\footdir@fntext}[1]{%
  \zifrefundefined{\thefootdir@label}{%
  }{%
    \edef\footdir@name{%
      footdir@\zref@extractdefault{\thefootdir@label}{abspage}{0}%
    }%
    \@ifundefined{\footdir@name}{%
      \expandafter\gdef\csname\footdir@name\endcsname{#1}%
    }{}%
  }%
}   
\newcommand*{\footdir@temp}[3]{%
  \@ifdefinable{#1}{%
    \let#1#2%
    \renewcommand{#2}[1]{%
      \footdir@write
      \footdir@fntext{#3}%
      \stepcounter{footdir@label}%
      \footdir@fntext{#3}%
      \footdir@toks{##1}% 
      \footdir@toks\expandafter{%
        \the\expandafter\footdir@toks
        \expandafter
        \zref@labelbyprops\expandafter{\thefootdir@label}{abspage}%
      }%
      \expandafter#1\expandafter{\the\footdir@toks}%
    }%
  }%  
}     
\footdir@temp\footdir@ORG@RTLfootnotetext\@RTLfootnotetext{R}%
\footdir@temp\footdir@ORG@LTRfootnotetext\@LTRfootnotetext{L}%
\def\footnoterule{%
  \footdir@LeftRightElse
    \left@footnoterule  
    \right@footnoterule 
    \left@footnoterule  
}
\makeatother

\begin{document}
\RTLfootnote{This is a test.}\LTRfootnote{This is a test.}
\newpage
\lipsum[1-4]
\LTRfootnotetext[3]{This is a test.}\RTLfootnote[4]{\lipsum[1-2]}
\newpage
Test with split footnote.
\newpage
\beginR 
\RTLfootnote{This is a test.}\LTRfootnote{This is a test.}
\endR
\newpage
\beginR 
\LTRfootnotetext[3]{This is a test.}\RTLfootnote[4]{This is a footnote.}
\endR
\end{document}

In this example, also the end of a footnote gets a label. If the end of the footnote falls on the next page, then \footdir@<absolute page number> is defined for that page.

Unsupported is the case, when a footnote split over more than two pages. This is much more complicate, because also the direction of the last footnote must be remembered and the page with the last footnote needs to be found.

share|improve this answer
    
Thanks a lot for the reply but when I run this, unlike you I get [footdir] 1: right [1] [footdir] 2: right [2] [footdir] 3: left [3] [footdir] 4: right. I run tex at least 3 times and I am having an updated TeXLive 2012. –  Vafa Oct 27 '12 at 23:53
    
@Vafa I had tested the case zref < 2012/10/27, but with my not yet released zref. The error should now be fixed. –  Heiko Oberdiek Oct 28 '12 at 6:46
    
Thanks a lot. This now works very well, however there is still one problem. If a footnote is split, say in pages 1 and 2, and the footnote is an RTL one, in page 1, we get RTL footnoterule (right) which is right but in page 2, we get LTR footnoterule (else) which is not right. What can be done in the case of split footnotes? –  Vafa Oct 28 '12 at 7:34
    
Thanks a lot Heiko. Please accept my +50 bounty. I was wondering if I could use this code of yours with some modifications in bidi package? –  Vafa Oct 28 '12 at 8:28
add comment

Due to lack of time, here is a first draft of numbering elements on a page.

\onopSet{<class>}{<id>}

The type of elements is given in <class> and the element is identified by <id> inside the class. \onopSet writes/constructs a zref label in the .aux file.

\onopGet{<class>}{<id>}

Expandable macro \onopGet expands to the ordinal number of the element <id> of class <class> on its page.

\onopUsed{<class>}{<id>}

is the companion macro for the expandable macro \onopGet and marks the reference as used in order to allow LaTeX to print an undefined reference warning if the reference do not yet exist.

\documentclass{article}
\usepackage{zref-abspage}
\usepackage{auxhook}

% Ordinal Number On Page/ OrdNumOnPage / onop

\makeatletter
\providecommand*{\c@zabspage}{\c@abspage}
\newcommand*{\onop@abspage}{\the\value{zabspage}}

\zref@newprop{OrdinalNumberOnPage}[0]{0}
\newcommand*{\onopSet}[2]{%
  \if@filesw
    \protected@write\@auxout{%
      \let\onop@abspage\relax
    }{%
      \protect\onopLabel{#1}{#2}{\onop@abspage}%
    }%
  \fi
}
\AddLineBeginAux{%
  \string\providecommand{\string\onopLabel}[3]{}%
}
\newcommand*{\onopLabel}[3]{%
  \@ifundefined{onop:#1:#3}{%
    \expandafter\xdef\csname onop:#1:#3\endcsname{1}%
    \onop@Clear{#1}{#3}%
  }{%
    \begingroup
      \count@=\csname onop:#1:#3\endcsname\relax
      \advance\count@\@ne
      \expandafter\xdef\csname onop:#1:#3\endcsname{\the\count@}%
    \endgroup
  }%
  \begingroup
  \edef\onop@tmp{\endgroup
    \noexpand\zref@newlabel{onop@#1@#2}{%
      \noexpand\abspage{#3}%
      \noexpand\OrdinalNumberOnPage{\csname onop:#1:#3\endcsname}%
    }%
  }\onop@tmp
}
\let\onop@AtBeginDocument\@empty
\newcommand*{\onop@Clear}[2]{%
  \expandafter
  \g@addto@macro\expandafter\onop@AtBeginDocument\expandafter{%
    \expandafter
    \global\expandafter\let\csname onop:#1:#2\endcsname\@undefined
  }%
}
\AtBeginDocument{%
  \onop@AtBeginDocument
  \let\onop@Clear\@gobbletwo 
}
\newcommand*{\onopUsed}[2]{%
  \zref@refused{onop@#1@#2}%
}
\newcommand*{\onopGet}[2]{%
  \zref@extract{onop@#1@#2}{OrdinalNumberOnPage}%
}
\newcommand*{\onopLabelName}[2]{%
  onop@#1@#2%
}   
\newcommand*{\onopGetAbsPage}[2]{%
  \zref@extract{onop@#1@#2}{abspage}%
}
\makeatother

\begin{document}
\section{Test}
\onopSet{footnote}{a}
\onopSet{footnote}{b}

\onopUsed{footnote}{a}
\onopUsed{footnote}{b}

a: \onopGet{footnote}{a}%
\ifnum\onopGet{footnote}{a}=1 %
  ~(first)%
\fi
,
b: \onopGet{footnote}{b}%   
\ifnum\onopGet{footnote}{b}=1 %
  ~(first)%
\fi
\end{document}
share|improve this answer
    
When you have time: how would this would work in my situation? I tried this but I am not sure how should it work for my purpose. –  Vafa Oct 24 '12 at 14: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.