Печать промежуточных итогов на каждой странице с помощью HTML/CSS/JS, возможно, XSLT?

Я хотел бы использовать открытые стандарты для печати отчетов, этот отчет должен будет содержать промежуточные итоги в конце каждой страницы.

Поток Использование XSL-FO, CSS3 вместо CSS2 для создания разбитых на страницы документов, таких как PDF?, указывает, что HTML с CSS3 - это путь.

Теперь проблема, которую я получаю, определяет с помощью HTML или CSS или с JS место, где будет заполняться страница А4, чтобы появилась страница.

Есть селектор разбиения страницы CSS:

page-break-before: always | avoid — always/avoid page breaks before the item
page-break-after: always | avoid — always/avoid page breaks after the item
page-break-inside: always | avoid — always/avoid page breaks in the middle of the item

Но они не очень полезны для целей промежуточных результатов на каждой странице, поскольку я не знаю, когда будет заполняться страница, чтобы я мог разместить там тег с таким CSS, который был применен к нему.

Тэг HTML TABLE поддерживает некоторые заголовки и нижние колонтитулы таблицы, которые кажутся многообещающими:

Строки таблицы могут быть сгруппированы в таблицу, стопку стола и одну или больше секций тела стола, используя элементы THEAD, TFOOT и TBODY, соответственно. Это подразделение позволяет агентам пользователей поддерживать прокрутку столовых тел независимо от головы стола и стопы. Когда таблицы печатаются, голова стола и информация о ноге могут быть повторяется на каждой странице, содержащей данные таблицы.

<TABLE>
<THEAD>
     <TR> ...header information...
</THEAD>
<TFOOT>
     <TR> ...footer information...
</TFOOT>
<TBODY>
     <TR> ...first row of block one data...
     <TR> ...second row of block one data...
</TBODY>
<TBODY>
     <TR> ...first row of block two data...
     <TR> ...second row of block two data...
     <TR> ...third row of block two data...
</TBODY>
</TABLE>

Но это опять-таки не очень полезно, так как те же нижние колонтитулы будут отображаться на всех страницах с одинаковыми промежуточными итогами, а не для каждой страницы. В противном случае я должен сделать таблицу с разными TFOOT и TBODY, статической структурой в соответствии с тем, когда страница заполнена... но я не могу получить такую ​​информацию, только количество строк, которые я мог бы указать при построении HTML Таблица. Я не вижу способа их создания, так как размер A4 соответствовал бы им.

Я не знаю, может, XSLT поможет здесь или javascript? Есть ли открытый стандарт CSS3, HTML5 или другое решение для этой проблемы, о котором я не знаю? Если нет, кто-нибудь знает обходной путь, примеры для решения этого вопроса?

Ответ 1

Это можно сделать с помощью обычного старого JavaScript, о чем свидетельствует приведенный ниже код.

<!DOCTYPE html>
<html>
  <body>
    <table class="data">
      <caption><b>MY TABLE</b></caption>
      <thead>
        <tr>
          <th>Col 1</th><th>Col 2</th>
        </tr>
      </thead>
      <tbody>
        <tr><td>1<td>1<tr><td>0<td>99<tr><td>1<td>1<tr><td>0<td>99<tr><td>1<td>1<tr><td>0<td>99
        <tr><td>2<td>9<tr><td>2<td>88<tr><td>2<td>0<tr><td>2<td>88<tr><td>2<td>0<tr><td>2<td>88
        <tr><td>3<td>1<tr><td>4<td>77<tr><td>3<td>1<tr><td>4<td>77<tr><td>3<td>1<tr><td>4<td>77
        <tr><td>4<td>8<tr><td>6<td>66<tr><td>4<td>1<tr><td>6<td>66<tr><td>4<td>1<tr><td>6<td>66
        <tr><td>5<td>1<tr><td>8<td>55<tr><td>5<td>1<tr><td>8<td>55<tr><td>5<td>1<tr><td>8<td>55
        <tr><td>6<td>7<tr><td>0<td>44<tr><td>6<td>2<tr><td>0<td>44<tr><td>6<td>2<tr><td>0<td>44
        <tr><td>7<td>1<tr><td>2<td>33<tr><td>7<td>1<tr><td>2<td>33<tr><td>7<td>1<tr><td>2<td>33
        <tr><td>8<td>6<tr><td>4<td>22<tr><td>8<td>3<tr><td>4<td>22<tr><td>8<td>3<tr><td>4<td>22
        <tr><td>9<td>1<tr><td>6<td>11<tr><td>9<td>1<tr><td>6<td>11<tr><td>9<td>1<tr><td>6<td>11
        <tr><td>1<td>0<tr><td>0<td>99<tr><td>1<td>4<tr><td>0<td>99<tr><td>1<td>4<tr><td>0<td>99
        <tr><td>2<td>1<tr><td>2<td>88<tr><td>2<td>1<tr><td>2<td>88<tr><td>2<td>1<tr><td>2<td>88
        <tr><td>3<td>1<tr><td>4<td>77<tr><td>3<td>1<tr><td>4<td>77<tr><td>3<td>1<tr><td>4<td>77
        <tr><td>4<td>5<tr><td>6<td>66<tr><td>4<td>5<tr><td>6<td>66<tr><td>4<td>5<tr><td>6<td>66
        <tr><td>5<td>1<tr><td>8<td>55<tr><td>5<td>1<tr><td>8<td>55<tr><td>5<td>1<tr><td>8<td>55
        <tr><td>6<td>4<tr><td>0<td>44<tr><td>6<td>6<tr><td>0<td>44<tr><td>6<td>6<tr><td>0<td>44
        <tr><td>7<td>1<tr><td>2<td>33<tr><td>7<td>1<tr><td>2<td>33<tr><td>7<td>1<tr><td>2<td>33
        <tr><td>8<td>3<tr><td>4<td>22<tr><td>8<td>7<tr><td>4<td>22<tr><td>8<td>7<tr><td>4<td>22
        <tr><td>9<td>1<tr><td>6<td>11<tr><td>9<td>1<tr><td>6<td>11<tr><td>9<td>1<tr><td>6<td>11
        <tr><td>1<td>2<tr><td>0<td>99<tr><td>1<td>8<tr><td>0<td>99<tr><td>1<td>8<tr><td>0<td>99
        <tr><td>2<td>1<tr><td>2<td>88<tr><td>2<td>1<tr><td>2<td>88<tr><td>2<td>1<tr><td>2<td>88
        <tr><td>3<td>0<tr><td>4<td>77<tr><td>3<td>9<tr><td>4<td>77<tr><td>3<td>9<tr><td>4<td>77
        <tr><td>4<td>1<tr><td>6<td>66<tr><td>4<td>1<tr><td>6<td>66<tr><td>4<td>1<tr><td>6<td>66
        <tr><td>5<td>1<tr><td>8<td>55<tr><td>5<td>0<tr><td>8<td>55<tr><td>5<td>0<tr><td>8<td>55
        <tr><td>6<td>1<tr><td>0<td>44<tr><td>6<td>1<tr><td>0<td>44<tr><td>6<td>1<tr><td>0<td>44
        <tr><td>7<td>0<tr><td>2<td>33<tr><td>7<td>1<tr><td>2<td>33<tr><td>7<td>1<tr><td>2<td>33
        <tr><td>8<td>1<tr><td>4<td>22<tr><td>8<td>1<tr><td>4<td>22<tr><td>8<td>1<tr><td>4<td>22
        <tr><td>9<td>0<tr><td>6<td>11<tr><td>9<td>2<tr><td>6<td>11<tr><td>9<td>2<tr><td>6<td>11
        <tr><!--Use this row for on-screen totals if needed; otherwise, leave it empty.-->
      </tbody>
    </table>
  </body>
</html>

<style>
  @media screen {
    .print {
      display: none; /*Prevents print version of table from showing on screen*/
    }
  }
  @media print {
    .data {
      display: none; /*Prevents screen version of table from showing in print*/
    }
    .print {
      display: block;
    }
    .print > .data {
      display: inline-table; /*Prevents page breaks better than page-break-inside: avoid;*/
      vertical-align: top;
    }
    /*The following rule makes rows opaque in IE even if background colors are disabled.*/
    .print.fixIE > .data > thead > tr > th:after,
    .print.fixIE > .data > tbody > tr:first-child > td:after {
      display: block;
      border-bottom: 18pt solid white; /*Border-width = line-height*/
      margin-top: -18pt; /*Negative line-height*/
      margin-right: -.5em; /*Negative td padding-right*/
      margin-left: -.5em; /*Negative td padding-left*/
      content: "";
    }
    .overlap {
      margin-bottom: -20pt; /*Negative row height (including borders)*/
    }
  }
  .data {
    table-layout: fixed; /*Columns must have fixed widths! Set with <col>s, if needed.*/
    width: 100%;
    border-spacing: 0;
    white-space: nowrap;
    font-size: 12pt;
    line-height: 18pt; /*If you change this, other CSS values must also be changed!*/
    border-right: 1pt solid black;
  }
  .data > thead > tr > th {
    border-top: 1pt solid black;
    border-left: 1pt solid black;
    background: white;
    padding: 0 .5em 0 .5em;
  }
  .data > tbody > tr > td {
    border-top: 1pt solid black; /*If you change this, .overlap must also be changed!*/
    border-left: 1pt solid black;
    background: white;
    padding: 0 .5em 0 .5em; /*If you change this, other CSS values must also be changed!*/
  }
  .data > tbody > tr:last-child > td {
    border-bottom: 1pt solid black; /*If you change this, .overlap must also be changed!*/
  }
  .data > tbody {
    text-align: right;
  }
</style>

<script>
  //This function takes two arguments:
  //1) a reference to a table element
  //2) an array of column indexes indicating which columns have numbers to be totalled.
  function printSubtotals(table, columns) {
    var
      tbody = table.tBodies[0],
      row = tbody.rows[0];
    if(!row)
      return;
    var cellCount = row.cells.length;
    if(!cellCount)
      return;
    var
      subtotals = [],
      rows = table.rows,
      thead = table.tHead,
      caption = table.querySelector('caption'),
      colgroup = table.querySelector('colgroup'),
      emptyTable = table.cloneNode(false),
      emptyRow = row.cloneNode(true),
      printDiv = document.createElement('div'),
      overlap = document.createElement('div'),
      subtotalCount = columns.length,
      rowCount = rows.length - 1,
      cells, subtotalCells, i, r;
    if(colgroup && colgroup.parentNode === table)
      emptyTable.appendChild(colgroup.cloneNode(true));
    emptyTable.appendChild(tbody.cloneNode(false));
    printDiv.className = /MSIE /.test(navigator.userAgent) ? 'print fixIE' : 'print';
    overlap.className = 'overlap';
    for(i = subtotalCount; i--; subtotals.push(0));
    for(i = cellCount; i--; emptyRow.cells[i].innerHTML = '');
    for(r = row.rowIndex; r < rowCount; r++) {
      printDiv.appendChild(overlap.cloneNode(true));
      tbody = printDiv.appendChild(emptyTable.cloneNode(true)).tBodies[0];
      cells = tbody.appendChild(rows[r].cloneNode(true)).cells;
      subtotalCells = tbody.appendChild(emptyRow.cloneNode(true)).cells;
      for(i = subtotalCount; i--;) {
        subtotals[i] += parseFloat(cells[columns[i]].innerHTML);
        subtotalCells[columns[i]].innerHTML = '<b>Total: ' + subtotals[i] + '</b>';
      }
    }
    printDiv.removeChild(printDiv.children[0]);
    tbody = printDiv.children[0].tBodies[0];
    if(caption && caption.parentNode === table)
      tbody.parentNode.insertBefore(caption.cloneNode(true), tbody);
    if(thead)
      tbody.parentNode.insertBefore(thead.cloneNode(true), tbody);
    table.parentNode.insertBefore(printDiv, table);
  }

  printSubtotals(document.querySelector('.data'), [0,1]);
</script>

Что делает функция Javascript, это создать версию только для печати таблицы, в которой каждая строка имеет скрытую промежуточную промежуточную строку, прикрепленную к ней. Строка промежуточных итогов закрывается следующей строкой, поэтому она видна только в том случае, если следующая строка попадает на следующую страницу или последняя строка в таблице. Это должно работать практически в любом браузере независимо от формата бумаги. Это может показаться неэффективным, но воспринимаемый выигрыш производительности ничтожно мал, поскольку таблица печати не отображается при загрузке страницы. Тем не менее, я бы не рекомендовал эту технику для таблиц со многими тысячами строк.

Обратите внимание, что приведенный выше код является просто доказательством концепции и, как таковой, не является особенно надежным. Несколько вещей, которые, как я знаю, нарушат это:

  • пустые ячейки в столбцах данных
  • нечисловые значения в столбцах данных
  • многострочный контент в ячейках tbody
  • изменение количества ячеек в строках tbody (например, некоторые из них имеют colspans, а другие нет)
  • разрешение содержимого ячейки определяет ширину столбца
  • изменение высоты линии или ширины границы без изменения других связанных значений CSS

Некоторые из этих вещей выполняются с правильными изменениями в JavaScript и CSS.