Forum How do I...?

Counters with long tables

tomilaurell
Hi,

What would be the recommended way to implement increasing counter with long table headers.

Table header on page X: Table_title (1/10)
Table header on page X+1: Table_title (2/10) etc.
And in this case table would be 10 pages long.

However if table does not overflow to the next page (all content fits to single page), the header should be just: Table_title

This will be used in dynamic pdf generation and for readability, it helps reader to know if table will continue and how long it will continue.

-Tomi
howcome
You can use the Prince box-tracking API combined with multi-pass to find on which page a table starts and ends. Here's a quick proof of concept:
<html>
<script>
Prince.trackBoxes = true;
Prince.registerPostLayoutFunc(postlayout);

function postlayout() {
   var elements = document.querySelectorAll('table');
   for(var i=0; i<elements.length; i++) { 
      var boxes = elements[i].getPrinceBoxes();
      var heading = elements[i].querySelector('th');
      for(var j=0; j<boxes.length; j++) { 
         heading.innerHTML += " "+boxes[j].pageNum;
      }
   }
}
</script>
<style>
@page { size: 100mm; margin: 10mm }
</style>
<body>
<table>
<tr><th>Table has content on these pages: 
<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo<tr><td>foo
</table>
<table>
<tr><th>Table has content on these pages: 
<tr><td>bar
</table>
</html>


More on multipass here:
https://www.princexml.com/doc/cookbook/#the-multi-pass-solution

Edited by howcome

tomilaurell
Hi,

Thanks for the reply. I used similar approach according to your hint:

Prince.trackBoxes = true;
Prince.registerPostLayoutFunc(function() {
  var tables = document.querySelectorAll('table');
  for (var i=0; i<tables.length; i++) {
    var boxes = tables[i].getPrinceBoxes();
    if (boxes.length > 1) {
      var headings = tables[i].querySelectorAll('div.widget_counter_title');
      for (var j=0; j<headings.length; j++) { 
        headings[j].innerHTML += " (" + (j+1) + "/" + boxes.length + ")";
      }
    }
  }
});


The html is:

<table>
<caption>
  <div class="widget_counter_title" >TITLE</div>
</caption>
<thead>....</thead>
<tbody>....</tbody>
</table>

However, now changing single caption will change all captions for the same table on all the pages. If I do just
tables[0].headings[0] += 'Trying to change this only' 

this same text will appear to: tables[0].headings[1], tables[0].headings[2], etc.

Did I miss something here? Box tracking api itself seems to work though.

I have tried to pass --max-passes=2 (same results) and --max-passes=1 (original document without changes)

NOTE:
I have used -prince-caption-page: all for table caption

Could this prince-caption-page setting have something to do here? Or should I style first row of thead as caption? I now try to modify this copied caption to have different content on each page.

-Tomi

Edited by tomilaurell

howcome
Try using "querySelector" (as in the example I provided) and not querySelectorAll.
tomilaurell
Hi,

Same results with querySelector

I used this exact script.

<script>
      Prince.trackBoxes = true;
      Prince.registerPostLayoutFunc(function() {
        var tables = document.querySelectorAll('table');
        for (var i=0; i<tables.length; i++) {
          var boxes = tables[i].getPrinceBoxes();
          if (boxes.length > 1) {
            var heading = tables[i].querySelector('div.widget_counter_title');
            var j=0;
            heading.innerHTML += " (" + (j+1) + "/" + boxes.length + ")";
          }
        }
      });
    </script>


I'm now thinking that maybe I should directly modify boxes and not DOM.
Something within here:
var boxes = tables[i].getPrinceBoxes();

-Tomi
tomilaurell
No - boxes cannot be modified directly. There must be something missing in this solution. Something I'm not aware.

-Tomi

Edited by tomilaurell

howcome
The sketched solution will work with "th" elements, but not "thead" -- "thead" will have the same content on all pages.

A workaround may be to use deferred page floats. These can be told to appear on the top of a page, they can "clear" the page, and they can have different content. Also, there's a way to delete elements, if there are too many. Here's a simple demo:

<html>
<head>
<style>
@page { size: 10cm 10cm }
div {
  -prince-float: top;
  -prince-clear: page;
  -prince-float-tail: fill-page;
}
</style>
</head>
<body>
<div class=p1>p1</div>
<div class=p2>p2</div>
<div class=p3>p3</div>
<div class=p4>p4</div>

<table>
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
<tr><td>foo<td>bar
</table>


Here's more on page floats:
https://www.princexml.com/howcome/2022/guides/float

Edited by howcome

tomilaurell
That does not really solve the issue. Tables can have any length: 1-50 pages. Only pdf knows how many pages it will have. And each page should have slightly different table caption (different counter value).

Best solution would be to have possibility to use counters in <caption> OR in <thead>
Now caption will have identical content on each page which basically means no support for counters.

I assume that there are others with same problem with the long tables.

Edited by tomilaurell

howcome
The suggested workaround will work for any number of pages. Here's an example with 36 pages:

https://www.wiumlie.no/2022/tests/table-header.pdf
https://www.wiumlie.no/2022/tests/table-header.html

If you make the table longer, you will see that more headers elements are automatically added (up to 100).

However, you will need to use the Javascript interface to change the content to reflect the number of pages.

Edited by howcome

tomilaurell
Hi,

Thanks for the example. Our case is more dynamic. If the table is aligned to the right side of the page, then header should be there also. Table captions handle these cases internally correct. Table just continues.

But yeah. I can see that it is possible to implement the case using your suggested solution. I would still like to make feature request of supporting counters in table captions.

But I can understand that using box tracking api I can find tables overflowing to next pages, then use absolute positioned table headers and add those to the html accordingly.

-Tomi