Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #5 from kthoden/dev-ou-footnotes
Add support for two sets of footnotes  (alphabetical and numbered).
  • Loading branch information
Klaus Thoden committed Apr 22, 2016
2 parents 3d07d55 + e361456 commit 0edbb80
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 8 deletions.
261 changes: 256 additions & 5 deletions Skripten/EOAconvert.py
Expand Up @@ -802,6 +802,34 @@ def cleanup():
dictFootnotes[strUID] = str(intNoteNumber)
intNoteNumber += 1


# the new-style footnotes that use LaTeX bigfoot show up in the following order:
footnote_groups = ["decimal", "lower-latin"]

def get_bigfoot_data(chapter):
"""
footnotes are per-chapter
footnote numbers reset for each chapter
this helper takes a chapter and returns a collection containing its new-style footnotes that use LaTeX bigfoot
the result is an association list: a list of key-value pairs
the values are, for each type of footnote, a list of the footnotes of that type, in the order in which they appear in the chapter
"""
xmlBigfootNotes = list(chapter.findall(".//EOAbigfoot"))
return [ # a list
( # of tuples
grouping, # the key
[ # the value: a filter of the above list
note
for note
in xmlBigfootNotes
if grouping == note.get("list-style-type")
],
)
for grouping
in footnote_groups # the types we support
]


print ("-----------------------------------------------------")
print ("Numbering of Lists per Chapter")
for xmlChapter in xmlChapters:
Expand Down Expand Up @@ -1486,14 +1514,166 @@ def cleanup():

print ("-----------------------------------------------------")
print ("Preparing Footnotes")

def alph_footnote_index(fndex):
"""
lowercase Latin footnotes need to support more than 26 values
These are zero-indexed.
>>> alph_footnote_index(0)
'a'
>>> alph_footnote_index(1)
'b'
>>> alph_footnote_index(24)
'y'
>>> alph_footnote_index(25)
'z'
>>> alph_footnote_index(26)
'aa'
>>> alph_footnote_index(27)
'ab'
"""
alphabet = "abcdefghijklmnopqrstuvwxyz"
quotient, remainder = divmod(fndex, len(alphabet))
if not quotient: return alphabet[fndex]
return alph_footnote_index(quotient - 1) + alph_footnote_index(remainder)


def replace_footnote_equations(footnote):
"""
captures reusable behavior from the existing code
potentially, some of the old code could be replaced by calls to this helper
usage: contentopf = replace_footnote_equations(my_footnote)
unfortunately, returning the result seemed like a better idea than mutating the global variable
"""
result = contentopf
for equation in footnote.findall(".//EOAequationnonumber"):
filename = equation.get("filename")
equation.clear()
equation.tag = "p"
img = etree.Element("img", src="images/%s" % filename, alt="")
equation.append(img)
cwd = os.getcwd()
shutil.copy("%s/items/%s" % (cwd, filename), "%s/CONVERT/epub/DEBPS/images/%s" % (cwd, filename))
result = addToContentopf(result, "images/" + filename, filename, "png")
return result


def replace_footnote_with_sup(note):
"""
captures reusable behavior from the existing code
potentially, some of the old code could be replaced by calls to this helper
this behavior showed up in a few places
I thought I would be able to extract a little more, but this was all that was actually common
"""
tail = note.tail
note.clear()
note.tail = tail
note.tag = "sup"


def bring_footnote_down_epub(footnote, footnote_name, destination):
"""
captures reusable behavior from the existing code
potentially, some of the old code could be replaced by calls to this helper
usage: contentopf = bring_footnote_down_epub(my_footnote, "1", xmlNewFootnotes)
unfortunately, returning the result seemed like a better idea than mutating the global variable
"""

contentopf = replace_footnote_equations(footnote) # see usage note
kids = list(footnote.getchildren())
prefix = "[%s]" % footnote_name

# we would like to prepend this footnote identifier to the footnote element
if footnote.text is not None:
# if the element starts with some text anyway, prepend it there
footnote.text = "%s %s" % (prefix, footnote.text)
else:
# if, however, the element begins with a child, prepend the text at the beginning of the first child instead
if len(kids):
first_child = kids[0]
child_text = prefix
# separate them with a space, unless the child had no text to begin with
child_suffix = first_child.text
if child_suffix is None:
child_suffix = ""
else:
child_text += " "
child_text += child_suffix
first_child.text = child_text
else:
# a totally empty footnote is weird, but who am I to judge?
footnote.text = prefix
footnote_text = footnote.text or ""
replace_footnote_with_sup(footnote)
footnote.text = "[%s] " % footnote_name
# append any text the footnote used to have to the destination
destkids = list(destination.getchildren())
if len(destkids):
# if the destination has children, append after the last one's tail
last_kid = destkids[-1]
prefix = last_kid.tail
if prefix is None:
prefix = ""
else:
prefix += " "
last_kid.tail = prefix + footnote_text
else:
# if the destination has no children, append to its text
prefix = destination.text
if prefix is None:
prefix = ""
else:
prefix += " "
destination.text = prefix + footnote_text
for kid in kids:
destination.append(kid)
return contentopf


class FootnoteError(Exception):
"""
we only support one type of footnote per chapter
don't try to mix-and-match
"""
pass


for xmlChapter in xmlChapters:
xmlFootnotes = xmlChapter.findall(".//note")
if len(xmlFootnotes) == 0:
continue
groupings = get_bigfoot_data(xmlChapter)
xmlFootnotes = list(xmlChapter.findall(".//note"))
has_old = 0 != len(xmlFootnotes)
has_new = 0 != len(
[ # flatten the association list whose values are lists, so we can take the length
note
for grouping, notes in groupings
for note in notes
]
)

# the XOR case falls through, the AND is an error, and the NOR skips to the next chapter
if has_old:
if has_new:
raise FootnoteError("Chapter %s contains both \\EOAfn and footnotes in the style of \\EOAfnalph" % xmlChapter.get("id-text"))
else:
if not has_new:
continue
xmlNewFootnotes = etree.Element("div")
xmlNewFootnotesHeader = etree.Element("h3")
xmlNewFootnotesHeader.text = dictLangFootnotes[xmlChapter.get("language")]
xmlNewFootnotes.append(xmlNewFootnotesHeader)
for grouping, notes in groupings:
# do for the new-style footnotes what was being done for the old
for index, note in enumerate(notes):
footnote_name = str(index + 1)
if "lower-latin" == grouping:
footnote_name = alph_footnote_index(index)
para = etree.Element("p")
contentopf = bring_footnote_down_epub(note, footnote_name, para)
xmlNewFootnotes.append(para)
intFootnoteNumber = 1
for xmlFootnote in xmlFootnotes:
# Not numbered Equations may appear in a footnote, need to be treated differently
Expand Down Expand Up @@ -2702,10 +2882,70 @@ def djangoParseHeadline(xmlElement):
print ("----------------------------------------------")
print ("Processing and linking Footnotes for django")

def bring_footnote_down_django(footnote, fragment, footnote_number, object_number, unique_id, destination):
"""
captures reusable behavior from the existing code
potentially, some of the old code could be replaced by calls to this helper
usage: intObjectNumber = bring_footnote_down_django(xmlFootnote, "fn"+str(intFootnoteNumber), str(intFootnoteNumber), intObjectNumber, tmpStrUID, xmlResult)
unfortunately, returning the result seemed like a better idea than mutating the global variable
"""

kids = list(footnote.getchildren())
footnote_text = footnote.text or ""
replace_footnote_with_sup(footnote)
footnote.set("class", "footnote")
anchor = etree.Element("a")
anchor.set("href", "#" + fragment) # "fn" + str(intFootnoteNumber)
anchor.text = footnote_number # str(intFootnoteNumber)
footnote.append(anchor)
foot = etree.Element("EOAfootnote")
foot.set("order", str(object_number))
object_number += 1
foot.set("number", footnote_number)
anchor_number = next(
iter(
(
parent.get("order")
for parent
in footnote.iterancestors()
if parent.get("order") is not None
)
)
)
foot.set("anchor", anchor_number)
foot.set("id", unique_id)
foot.text = footnote_text
for kid in kids:
if "EOAequationnonumber" == kid.tag:
cwd = os.getcwd()
shutil.copy(
"%s/items/%s" % (cwd, kid.get("filename")),
"%s/CONVERT/django/images/" % cwd,
)
foot.append(kid)
destination.append(foot)
return object_number


xmlEOAchapters = xmlEOAdocument.findall(".//EOAchapter")
for xmlEOAchapter in xmlEOAchapters:
if len(xmlEOAchapter.findall(".//note")) == 0:
continue
groupings = get_bigfoot_data(xmlEOAchapter)
has_old = 0 != len(xmlEOAchapter.findall(".//note"))
has_new = 0 != len(
[ # flatten
note
for grouping, notes in groupings
for note in notes
]
)
# XOR falls through, AND is an error (that should have already been thrown during the epub phase), and NOR skips to the next chapter
if has_old:
if has_new:
raise FootnoteError("This chapter contains both old-style footnotes and new-style footnotes")
else:
if not has_new:
continue
# Find out running order of last item the chapter
# Hier pro FN zunächst die EOAequationnonumber in <p> korrigieren
# Dann pro FN die Kindelemente abarbeiten und an die neue FN dran hängen
Expand All @@ -2722,6 +2962,17 @@ def djangoParseHeadline(xmlElement):
xmlHead.text = dictLangFootnotes[xmlEOAchapter.get("language")]
xmlEOAsection.append(xmlHead)
xmlResult.append(xmlEOAsection)

for grouping, notes in groupings:
for index, note in enumerate(notes):
# do for the new-style notes what the old code did for the other footnotes
fntext = str(index+1)
if "lower-latin" == grouping:
fntext = alph_footnote_index(index)
unique_id = "fn%s" % fntext
intObjectNumber = bring_footnote_down_django(note, unique_id, fntext, intObjectNumber, unique_id, xmlResult)

intFootnoteNumber = 1
xmlFootnotes = xmlEOAchapter.findall(".//note")
for xmlFootnote in xmlFootnotes:
xmlFootnoteContent = xmlFootnote.getchildren()
Expand Down
28 changes: 25 additions & 3 deletions TeX/pre_eoa.tex
@@ -1,6 +1,5 @@
% Version: 1.5
% 14/07/2015
% Last modifier: Georg
% Version: 1.5+
% Last modified: March 2016

\documentclass[10pt,openright,twoside]{scrbook}

Expand Down Expand Up @@ -372,6 +371,8 @@
}
% New command for numbered chapters
\newcommand{\EOAchapter}[2]{
\setcounter{footnotealph}{0}
\setcounter{footnotearabic}{0}
\chapter[#2]{#2}
\chaptermark{#1}
\ifthenelse{\boolean{anthology}}{
Expand Down Expand Up @@ -611,3 +612,24 @@
\setlength\emergencystretch{3em}
\usepackage[german=quotes]{csquotes}
%%%%%%%%%%%% Footnote Sets
\usepackage{etex}
\usepackage{bigfoot}
\usepackage{alphalph}
% Allocate some extra registers so that we don't run out when
% declaring footnotes
\reserveinserts{4}
\DeclareNewFootnote{arabic}[arabic]
\DeclareNewFootnote{alph}[alph]
%allow for more than 26 alpha-numbered footnotes per chater
%(aa,ab,ac,...)
\renewcommand{\thefootnotealph}{\emph{\alphalph{\value{footnotealph}}}}
\newcommand{\EOAfnalph}[1]{\protect\footnotealph{#1}}
\newcommand{\EOAfnarabic}[1]{\protect\footnotearabic{#1}}
%%%%%%%%%%%% Footnote Sets --end
3 changes: 3 additions & 0 deletions TeX/pre_xml.tex
Expand Up @@ -268,3 +268,6 @@
%EOAtablehead
\newcommand*{\EOAtablehead}[2][1]{\begin{xmlelement}{tableheader}TRUE\end{xmlelement}#2\\}
\newcommand*{\EOAfnarabic}[1]{\begin{xmlelement}{EOAbigfoot}\AddAttToCurrent{list-style-type}{decimal}#1\end{xmlelement}}
\newcommand*{\EOAfnalph}[1]{\begin{xmlelement}{EOAbigfoot}\AddAttToCurrent{list-style-type}{lower-latin}#1\end{xmlelement}}

0 comments on commit 0edbb80

Please sign in to comment.