Section Titles (H1) in Header for PDF Export

I’m having a hard time. I’ve tried multiple ways but I don’t think I understand the rendering phases for PDF well enough. To do this with JavaScript I need to be able to see the page after the page breaks are in place. When I try to retrieve the DOM elements representing all my page headers it is returning just one whether I use…

require(['xwiki-page-ready'], function(pageReady) {

or add…

pageReady.afterPageReady(() => {

or add to that…

return new Promise((resolve, reject) => {

I’m seeing the page before the pagination. Obviously when the table of contents (TOC) is being built and pages are being set, it has exactly the data that I need, since this is generally the last item on the TOC for the page number preceding the current page.

Not accounting for a few details I’m just trying to set the last “h1” section text as part of my page header to indicate that the current page starts within the middle of the section, i.e. instead of just the document title in each page’s header something like: “<document title> - <current section>” (where <current section> is the text content of the last h1 element). I can’t even get that far, but a nuance is excluding the “Table of Contents” literal text which is in an h1 element coming before the first page of content, or when an h1 is the first content on a new page following a page break the last section title should be excluded from the header. I could deal with those cases maybe if I could just get the basic functionality working.

I tried doing this with JavaScript within the PageReady steps shown above this way. “hs “ is always printed with a length of 1 though in the finished document the span with class “pdf-chapter-name” occurs many times, showing that my script is running before the pages with headers have been set up:

```
var sectionHeadings = document.getElementsByTagName('h1');
console.info('shs '+sectionHeadings.length);
var i = 0;
var previousSectionHeading = null;
var sectionHeading = sectionHeadings[i];
console.info('sh '+sectionHeading.outerHTML);

var headers = document.getElementsByClassName('pdf-chapter-name');
console.info('hs '+headers.length);
for(var i2 = 0; i2< headers.length; i2++){
  var header = headers[i2];
  console.info('h '+header.outerHTML);
  while(sectionHeading !== null && (header.compareDocumentPosition(sectionHeading) & Node.DOCUMENT_POSITION_PRECEDING)) {
    i = i+1;
    previousSectionHeading = sectionHeading;
    sectionHeading = sectionHeadings[i];
    console.info('sh '+sectionHeading.outerHTML);
  }
  if(previousSectionHeading !== null){
    let newSpan = document.createElement('span');
    newSpan.innerText = previousSectionHeading.innerText;
    header.after(newSpan);
  }
}

I thought about trying to pull from the table of contents page, but I suspect I’d have the same problem and the content doesn’t exist yet when my javascript would run.

I tried doing it in LESS but lazy loading is killing me, because I can’t get the sequence

h1 {
  string-set: section-name content(text);`
}

is kind of close, but often one off. So I tried something like (syntax may be wrong)…

h1 {
  string-set: previous-section-name string(section-name);
  string-set: section-name content(text);
}

doesn’t work because these aren’t done in sequence but through lazy loading, so I think when I get the syntax right what happened was previous-section-name and section-name are the same, since it evaluates section-name on reference.

Hi,

If you want to show the current section name for a given level in the PDF header then you should first break the print page before any section of that level. In doesn’t make sense to mix multiple sections of the same level in the same print page if the header shows the name of a single section, which might not even start on that print page.

break-before: page;

Once you do this, then:

string-set: section-name content(text);

should work as expected because for each print page you can have:

  • either the section name is on that page (i.e. the section starts on that page)
  • or there is no section name (of that level) on that page, because the section continues on that page (it has started on a previous print page)

In both cases string-set will set the section-name to the name of the current section (that started on the current print page or a previous print page).

Adding a separator between the wiki page title and the section name, in the PDF header, is a bit tricky, because paged.js currently doesn’t support passing multiple values to string-set, as in:

string-set: section-name ' \00A7 ' content(text);

but you can use other styling to separate the two.

Hope this helps