Forum How do I...?

Block elements in paragraphs footnotes

groverdill
I am using prince to lay out a document with paragraphs that contain some "chatty" footnotes, some of which contain elements like tables.

My main body paragraphs are marked up using [p] tags and my footnote tags are marked up using [span] tags, which seems to make a lot of semantic sense. However html doesn't like block-level elements like [table] to be placed in inline containers like p or span, so everything explodes as soon as it gets to the block level element in my footnote span.

The only way I can think to make this work is potentially to markup all my paragraphs as individual divs (so, use <div> instead of <p> everywhere I have a paragraph), but that feels pretty gross. Is there a better way?

I have attached some example code that demonstrates what I'm trying to do.
  1. footnote_test.html1.3 kB
    source html
  2. footnote_test.pdf38.1 kB
    generated pdf
mikeday
The other approach would be to use "display: inline-table" on nested spans instead of actual table elements, if that's any better. (Or XML which allows arbitrary element nesting, although that can introduce issues of its own).
groverdill
Thanks Mike! I've done some experiments with display: inline-table and it looks like that is going to get me where I want to go for my footnotes. There's a bit more markup and styling this way, but at least its all contained in the footnote span itself and doesn't require changes in the parent element (so I don't have to change a bunch of random p tags to divs just to format the footnote contents inside them).

Thanks again for pointing me in the right direction. I will attach the updated files in case someone wants to look at them.
  1. footnote_test_updated.html2.2 kB
    updated source html
  2. footnote_test_updated.pdf38.1 kB
    updated generated pdf
SteelWagstaff
We have run into a very similar problem with books that we're formatting as PDFs. Authors using our publishing platform would like to be able to include block elements within footnotes, but we've historically always marked up footnotes as `<span>` (i.e. inline) elements. The problem we run into is when users try to include block elements like multiple paragraphs, ordered/unordered lists, or block quotes in their footnotes. We've been using Prince since early days and know there's been a lot of development here. Does Prince now support the use of footnote content in a block element (say a <div>) rather than a span? If so, how can we safely do this?
mikeday
The tricky part is that Prince allows this via the CSS display property, but HTML syntax does not allow nesting blocks within spans and is unaware of the CSS, so it breaks the markup.

I think it would be possible to solve this with JavaScript, in which the footnote block content is elsewhere in the document and a script moves it into place, allowing a block to be inside a span without breaking everything.
SteelWagstaff
Hi Mike, thanks for your answer. In our case, our output looks something like this:
<p>I'm a sentence.<span class="footnote">I'm a footnote. <ul><li>I'm a list item</li><li>I'm another list item</li></ul><p>I'm the second paragraph in this footnote.</p></span> I'm another sentence in the original paragraph.</p>

We can't safely change the <span class="footnote"> to be a <div class="footnote"> because <p> elements can't properly contain divs (https://stackoverflow.com/a/8398003). The goal is to make the footnote container itself a block element (so that it can contain other block elements without becoming invalid HTML). Not sure what you're suggesting here, but I'm curious. Are you suggesting leaving the footnote as a span, moving it to the bottom of the page and then transforming it into a block somehow? I'm a bit lost.

In our case, the publishing platform is built on WordPress, and our footnotes are actually constructed with shortcodes, so the user input actually looks like this: [footnote]I'm a footnote. <ul><li>I'm a list item</li><li>I'm another list item</li></ul><p>I'm the second paragraph in this footnote.</p>[/footnote]. We have total control over how the shortcode is processed and turned into the span output in case that's useful to know.
markbrown
Here's an example. The footnote elements are placed outside the <p> elements so as not to break the html, and are linked by another element with class "indirect". The script moves any footnotes into their correct places.

<script>
ind = document.getElementsByClassName("indirect");
for (var i=0; i<ind.length; i++) {
    var e = document.getElementById(ind[i].getAttribute("ref"));
    if (e) ind[i].appendChild(e);
}
</script>

<p>
A paragraph containing a footnote.<span style="float: footnote;">
    <span class="indirect" ref="fn1"></span>
</span>
Content in the same paragraph.
</p>

<div id="fn1">
    <ul>
        <li>Block content in a footnote
        <li>doesn't interrupt flow
    </ul>
</div>
SteelWagstaff
Thanks Mark -- this looks very promising!
SteelWagstaff
Hi Mark & Mike --
we've spent a few days trying to get a sample implementation based on the suggestion above. It works well when a footnote occurs at the end of a paragraph, but we're still running into the same problem when the footnote occurs in the middle of a paragraph, as in the example above. As I understand it, the problem is that when the div is appended to the indirect span element inside of the paragraph, the paragraph element is forcibly closed and a new paragraph element appears to encapsulate the remainder of the text. I think the reason for this is explained fairly well here: https://stackoverflow.com/a/10763952.

So in the example above
<p>
A paragraph containing a footnote.<span style="float: footnote;">
    <span class="indirect" ref="fn1"></span>
</span>
Content in the same paragraph.
</p> 

becomes
<p>
A paragraph containing a footnote.</p><span style="float: footnote;">
    <span class="indirect" ref="fn1"><div>...</div></span>
</span>
<p>Content in the same paragraph.
</p>

We're stuck in the same place as before, frankly. The presence of a div with footnote content just simply isn't allowed by the browser inside of the p element. We're stumped and are on the verge of telling authors that they simply cannot include block elements within their footnotes, unless someone has a better idea/workaround?
markbrown
My guess is that the javascript is being run elsewhere before it gets to Prince, which is why you are getting back to the same place as before.

Can you try the following slight variation? This should ensure the script is only run once it gets to Prince.

<script>
function replaceIndirect() {
    ind = document.getElementsByClassName("indirect");
    for (var i=0; i<ind.length; i++) {
        var e = document.getElementById(ind[i].getAttribute("ref"));
        if (e) ind[i].appendChild(e);
    }
}

if (typeof Prince != "undefined") {
    replaceIndirect();
}
</script>
...