How to add an HTML element at the bottom of the last page of a webkit report

Tags:

Introduction

report_webkit is an odoo (formerly OpenERP) module that uses the wkhtmltopdf tool to render mako templates into PDF reports.

It includes multiple headers, footers and logos, javascript support, CSS support and other features.

Sometimes you want to print an element of the report at the bottom of the last page of the report. Take for instance the customer’s signature on a quotation. You need to print the 'Signature:' string once, but if you put it at the end of the mako template, it could be printed in the centre of the page: it depends on the number of lines of the quotation.

The code

Let’s see how to solve this using the standard footer of a webkit report.

<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
<script>
function subst() {
    var vars={};
    var x=document.location.search.substring(1).split('&');
    for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
    var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
    for(var i in x) {
        var y = document.getElementsByClassName(x[i]);
        var signature_div = document.getElementsByClassName('signature')[0];
            if (vars['page'] == vars['topage']) {
                signature_div.style.visibility="visible";
            }
        for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
    }
}
</script>
</head>
<body style="border:0; margin: 0;" onload="subst()">
    <div class="signature" style="visibility:hidden;">Signature:</div>
    <table style="border-top: 1px solid black; width: 100%">
        <tr >
        <td style="text-align:right;font-size:12;" width="95%">
            Page <span class="page"/>
        </td>
        <td style="text-align:left;font-size:12;"> of <span class="topage"/></td>
        </tr>
    </table>
</body>

The interesting part is the element

<div class="signature" style="visibility:hidden;">Signature:</div>

and the javascript

var signature_div = document.getElementsByClassName('signature')[0];
    if (vars['page'] == vars['topage']) {
        signature_div.style.visibility="visible";
    }

This allows to use, within the footer, a div element that is always hidden, except when vars['page'] == vars['topage'], that is when we are on the last page of the report.

That’s all 🙂

Update March 2016

The module report_qweb_element_page_visibility is available.

From its description:

This module allows you to use 4 classes in QWEB reports:

  • not-first-page: shows element in every page but first
  • not-last-page: shows element in every page but last
  • first-page: shows element only on first page
  • last-page: shows element only on last page
Facebook Twitter Linkedin Digg Delicious Reddit Stumbleupon Tumblr Posterous Email Snailmail

Written by on Tuesday, May 27th, 2014

Lorenzo Battistini
OpenERP addicted
GitHub profile: https://github.com/eLBati
Launchpad profile: https://launchpad.net/~elbati
Linkedin profile: http://www.linkedin.com/in/elbati
------------------------------------------------
Agile Business Group
  • http://profile.e-ware.org/ Francesco Scapigliato

    Grazie mille Lorenzo. Era da tempo che attendevo un articolo così!

  • Valentin LAB

    You should probably:

    – move out the two lines about “signature_div“ out of the “for“. Since there are no reason to be included there, and they will get executed as many times (7 times) there are elements in “x“ array, for no reasons.
    – in your current example, move the “.getElementsByClassName“ in the “if“ (no need to fetch the element if you already know that you won’t need to change it), or…
    – set visibility to “hidden“ when it should be hidden via js to avoid having two different places tinkering with visibility.

    In last version of odoo, version 8 (or saas-6), to enable special class names to do special things (as for instance a ‘last-page’ class name to trigger visibility), you should only modify “report“ module, in “static/src/js/subst.js“, and add this code to the “subst“ function:


    var operations = {
    'last-page': function (elt) { elt.style.visibility = (vars.page === vars.topage) ? "visible" : "hidden"; },
    };

    for (var klass in operations) {
    var y = document.getElementsByClassName(klass);
    for (var j=0; j<y.length; ++j) operations[klass](y[j]);
    }

    In the QWEB “ir.ui.views“ used by your report, you can then add anywhere (header, body, footer), code with:

    My content only displayed if on last page.

    Adding other operations is quite easy with this structure. For instance, “first-page“, “odd-page“ … or any other variation could be easily done by adding a proper line in the operations. Some people would probably also prefer to set “display: none“ to remove the space taken by the box. You could allow both possibility with “display-last-page“ and “visiblity-last-page“ classes. The code is straightforward. You could even do a “last-page-set-class-myclass“ to set a CSS class on conditions.

    Hope this helps others,

    Thank you for your original post !

    • Anil Kesariya

      Thank you very much for sharing this. this helped me a lot. 🙂

    • Jean-Charles Drubay

      Nice page and answers. I think one point is still unsolved so…

      I am part of the people who would prefer to set “display: none“ to remove the space taken by the box. But when doing so, the rest of the content of my footer just moves up, and the footer of all pages have the same size (which is too big for all pages except the last one).

  • Anil Kesariya

    Nice Blog! how to apply the same for qweb report?