diff --git a/_sass/template/partials/_print-notes.scss b/_sass/template/partials/_print-notes.scss index c81a1bcb..fd3264e0 100644 --- a/_sass/template/partials/_print-notes.scss +++ b/_sass/template/partials/_print-notes.scss @@ -42,32 +42,54 @@ $print-notes: true !default; margin: ($line-height-default * 0.75) 0 0 0; } + // The page-footnotes area + @page { + counter-reset: manual-footnote; + + @footnote { + border-top: $rule-thickness solid $color-text-main; + margin-top: $line-height-default / 2; + padding-top: $line-height-default / 2; + font-size: $font-size-default * $font-size-smaller; + } + } + // True footnotes (we call them page-footnotes for clarity) // For styling see https://www.princexml.com/doc-prince/#footnote-calls + + // The numbers in front of footnote text + *::footnote-marker { + float: left; + font-size: $font-size-default * $font-size-smaller; + width: 0; + } + + // The page-footnote references in body text + // Note that other styling is defined in + // _print-base-typography.scss + *::footnote-call { + content: counter(footnote); + font-size: $font-size-default * 0.7; + vertical-align: super; + line-height: none; + + // Shift down + top: $font-size-default / 4; + position: relative; + } + .page-footnote { float: footnote; font-size: $font-size-default * $font-size-smaller; - footnote-style-position: inside; + footnote-style-position: inside; // a prince-only property text-indent: -($paragraph-indent); margin-left: $paragraph-indent; - // Rule above - &:first-of-type { - border-top: $rule-thickness solid $color-text-secondary; - padding-top: $line-height-default; - } + p { margin-bottom: 0; text-indent: 0; - &:first-of-type { - } } } - // The numbers in front of footnote text - *::footnote-marker { - float: left; - font-size: $font-size-default * $font-size-smaller; - width: 0; - } // Avoid page-footnotes created by footnotes.js // from inheriting blockquote indentation by @@ -77,26 +99,29 @@ $print-notes: true !default; margin-left: $paragraph-indent; } - // The page-footnotes area - @page { - @footnote { - margin-top: $line-height-default / 2; - padding-top: $line-height-default / 2; - font-size: $font-size-default * $font-size-smaller; + // Footnotes created with one-by-one 'move-to-footnote' + // class need a different kind of counter, because + // in a document with some endnotes and some manual footnotes, + // they need to have a different numbering system. + // Otherwise, they'll appear at the bottom of the page + // but be numbered in order with the endnotes. + + .page-footnote { + counter-increment: manual-footnote; + + &::footnote-call { + content: counter(manual-footnote, asterisks); + font-size: $font-size-default * 0.7; + vertical-align: super; + line-height: none; + + // Shift down + top: $font-size-default / 4; + position: relative; } - } - // The page-footnote references in body text - // Note that other styling is defined in - // _print-base-typography.scss - *::footnote-call { - content: counter(footnote); - font-size: $font-size-default * 0.7; - vertical-align: super; - line-height: none; - // Shift down - top: $font-size-default / 4; - position: relative; + &::footnote-marker { + content: counter(manual-footnote, asterisks); + } } - } diff --git a/assets/js/footnotes.js b/assets/js/footnotes.js index 7158b687..c10ea02f 100644 --- a/assets/js/footnotes.js +++ b/assets/js/footnotes.js @@ -1,105 +1,161 @@ -// Move footnotes to bottoms of pages - -console.log('Checking for footnotes to move to endnotes...'); - -function ebFootnotesToMove() { - 'use strict'; - // If there are any footnotes... - if (document.querySelector('.footnotes')) { - // And if the page-footnotes setting is on, - // or at least on for one of the footnotes - if (document.body.hasAttribute('data-page-footnotes') || - document.querySelector('.footnotes .page-footnote')) { - return true; - } +/* eslint no-var: off */ + +// The above comment is necessary because Prince 11 +// can't use let and const, as Standard JS would prefer. + +// Move footnote text to the bottoms of pages by moving them +// from the end of the document (where kramdown gathers them) +// to a container div beside their in-text references. + +// A counter for footnote references created one-by-one, +// rather than for an entire page or books. +var manualFootnoteCounter = 1 + +function ebFootnotesToMove (wrapper) { + 'use strict' + + // If there are any footnotes ... + if (wrapper.querySelector('.footnotes')) { + // ... and if the page-footnotes setting is on, + // or at least on for one of the footnotes + if (wrapper.hasAttribute('data-page-footnotes') || + wrapper.querySelector('.footnotes .move-to-footnote')) { + // ... then return true + return true } + } } -function ebMoveEndnoteToFootnote(noteReference) { - 'use strict'; +function ebMoveEndnoteToFootnote (noteReference) { + 'use strict' + + // Get the footnote ID + var footnoteReferenceID = noteReference.hash + + // NOTE: Prince's .hash behaviour is unusual: it strips the # out. + // So, let's use getElementById instead of querySelector. + // If it starts with a hash, chop it out. + if (footnoteReferenceID.indexOf('#') === 0) { + footnoteReferenceID = footnoteReferenceID.replace('#', '') + } + + // Find the li with the ID from the .footnote's href + var endnote = document.getElementById(footnoteReferenceID) + + // Check that we should actually process this footnote. + // If the data-page-footnotes setting isn't applied to this doc... + var wrapper = noteReference.closest('.wrapper') + if (!wrapper.hasAttribute('data-page-footnotes')) { + // ...check whether this particular footnote should be moved. + if (!endnote.querySelector('.move-to-footnote')) { + endnote.classList.add('endnote-text') + noteReference.classList.add('endnote-reference') + return + } + } - var footnoteReferenceID, endnote, pageFootnote, - containingElement, footnoteReferenceContainer; + // Make a div.page-footnote + var pageFootnote = document.createElement('div') + // pageFootnote.className += ' page-footnote' + pageFootnote.classList.add('page-footnote') + pageFootnote.id = footnoteReferenceID - // get the footnote ID - footnoteReferenceID = noteReference.hash; + // Add and increment the manual-footnote counter + if (endnote.querySelector('.move-to-footnote')) { + pageFootnote.setAttribute('page-footnote-counter', manualFootnoteCounter) + manualFootnoteCounter += 1 + } - // NOTE: Prince's .hash behaviour is unusual: it strips the # out - // So, let's use getElementById instead of querySelector. - // If it starts with a hash, chop it out. - if (footnoteReferenceID.indexOf('#') === 0) { - footnoteReferenceID = footnoteReferenceID.replace('#', ''); - } + // Get the sup that contains the footnoteReference a.footnote + var footnoteReferenceContainer = noteReference.parentNode - // Find the li with the ID from the .footnote's href - endnote = document.getElementById(footnoteReferenceID); + // Get the element that contains the footnote reference + var containingElement = noteReference.parentNode.parentNode - // Check that we should actually process this footnote. - // If the data-page-footnotes setting isn't applied to this doc... - if (!document.body.hasAttribute('data-page-footnotes')) { - // ...check whether this particular footnote should be moved. - if (!endnote.querySelector('.move-to-footnote')) { - return; - } - } + // and add a class to it. + containingElement.parentNode.className += ' contains-footnote' - // Make a div.page-footnote - pageFootnote = document.createElement('div'); - pageFootnote.className += ' page-footnote'; - pageFootnote.id = footnoteReferenceID; + // Move the endnote contents inside the div.page-footnote + pageFootnote.innerHTML = endnote.innerHTML - // Get the sup that contains the footnoteReference a.footnote - footnoteReferenceContainer = noteReference.parentNode; + // Insert the new .page-footnote at the reference. + // Technically, before the that contains the reference . + // We have to use insertBefore because Prince borks at insertAdjacentElement. + containingElement.insertBefore(pageFootnote, footnoteReferenceContainer) - // Get the element that contains the footnote reference - containingElement = noteReference.parentNode.parentNode; + // Remove the old endnote, and the old reference to it + // (Prince creates new references to page-footnotes) + endnote.parentNode.removeChild(endnote) + footnoteReferenceContainer.parentNode.removeChild(footnoteReferenceContainer) +} - // and add a class to it. - containingElement.parentNode.className += ' contains-footnote'; +function ebFootnotesRenumberEndnotes () { + 'use strict' + + // Get all the endnote lists in the doc + var endNoteLists = document.querySelectorAll('div.footnotes ol') + + // For each list, update the endnote numbers + endNoteLists.forEach(function (list) { + var endnoteListItems = list.querySelectorAll('li.endnote-text') + + // If we moved any notes to on-page footnotes with .move-to-footnote, + // and we still have a list of endnotes, then we must renumber the endnote + // references, because now the reference numbers will not match the + // auto-numbered list of endnotes. + // Note that the endnote *references* might be repeated (e.g. two places + // in the text that refer to the same endnote). + + var i + for (i = 0; i < endnoteListItems.length; i += 1) { + var endnoteNewNumber = i + 1 + var endnoteOldID = endnoteListItems[i].id + var endnoteNewID = endnoteOldID.replace(/fn:\d+$/, 'fn:' + endnoteNewNumber) + var endnoteReferences = document.querySelectorAll('[href="#' + endnoteOldID + '"]') + + // Update all the endnote references that refer to the old number + endnoteReferences.forEach(function (reference) { + reference.innerHTML = endnoteNewNumber + reference.hash = endnoteNewID + }) + + // Update the IDs of the endnotes sequentially + endnoteListItems[i].id = endnoteListItems[i].id.replace(/fn:\d+$/, 'fn:' + endnoteNewNumber) + } + }) +} - // Move the endnote contents inside the div.page-footnote - pageFootnote.innerHTML = endnote.innerHTML; +function ebEndnotesToFootnotes (wrapper) { + 'use strict' - // Insert the new .page-footnote at the reference. - // Technically, before the that contains the reference . - // We have to use insertBefore because Prince borks at insertAdjacentElement. - containingElement.insertBefore(pageFootnote, footnoteReferenceContainer); + // Get all the a.footnote links we want to move + var footnoteReferences = wrapper.querySelectorAll('.footnote') - // Remove the old endnote, and the old reference to it - // (Prince creates new references to page-footnotes) - endnote.parentNode.removeChild(endnote); - footnoteReferenceContainer.parentNode.removeChild(footnoteReferenceContainer); + // Process all those footnotes + var i + for (i = 0; i < footnoteReferences.length; i += 1) { + ebMoveEndnoteToFootnote(footnoteReferences[i]) + if (i === footnoteReferences.length - 1) { + console.log('On-page footnotes moved. Now to renumber endnotes ...') + ebFootnotesRenumberEndnotes() + } + } } -function ebEndnotesToFootnotes() { - 'use strict'; - - // get all the a.footnote links - var footnoteReferences = document.querySelectorAll('.footnote'); - - // Process all the footnotes - var i; - for (i = 0; i < footnoteReferences.length; i += 1) { - ebMoveEndnoteToFootnote(footnoteReferences[i]); - - // // If page-footnotes are on for the document, - // // move all the endnotes to page footnotes - // if (document.body.getAttribute('data-page-footnotes')) { - // ebMoveEndnoteToFootnote(footnoteReferences[i]); - // } else { - // // If a given endnote contains .move-to-footnote, - // // move that one endnote. - // console.log('footnoteReferences[i].innerHTML: ' + footnoteReferences[i].innerHTML); - // if (footnoteReferences[i].querySelector('.move-to-footnote')) { - // ebMoveEndnoteToFootnote(footnoteReferences[i]); - // } - // } +// If there are footnotes to move, move them. +function ebFootnotesForPDF () { + 'use strict' + + var wrappers = document.querySelectorAll('.wrapper') + + wrappers.forEach(function (wrapper) { + if (ebFootnotesToMove(wrapper)) { + console.log('We have endnotes to move to page footnotes ...') + ebEndnotesToFootnotes(wrapper) } + }) } -/// If there are footnotes to move, move them. -if (ebFootnotesToMove()) { - console.log('Yes, we have footnotes to move...'); - ebEndnotesToFootnotes(); -} +// Go +ebFootnotesForPDF()