diff --git a/Skripten/EOAconvert.py b/Skripten/EOAconvert.py index 422d2cc..f86a6bd 100755 --- a/Skripten/EOAconvert.py +++ b/Skripten/EOAconvert.py @@ -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: @@ -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 @@ -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

korrigieren # Dann pro FN die Kindelemente abarbeiten und an die neue FN dran hängen @@ -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() diff --git a/TeX/pre_eoa.tex b/TeX/pre_eoa.tex index 9171305..7b893a9 100755 --- a/TeX/pre_eoa.tex +++ b/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} @@ -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}}{ @@ -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 diff --git a/TeX/pre_xml.tex b/TeX/pre_xml.tex index 50de11c..3c85caa 100644 --- a/TeX/pre_xml.tex +++ b/TeX/pre_xml.tex @@ -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}}