The current PDF command and its corresponding pdf.default template does not allow to define a footer for the pages of the document.
Please add support for a footer in a way that we can define custom html for it and also allow us to insert things like page number and total number of pages into that html.
Additionally the generated TOC should optionally have page numbers.
wkthmltopdf that you use has support for all of the above. The challenge is probably, how to add this features without leaking the implementation details of wkhtmltopdf into docfx.
I have managed to add footers with page numbers with this change: https://github.com/bitbonk/docfx/commit/1ad6e004cd854eb968ce5bc94cd3e4d3aaadcece
And this footer.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body onload="substitutePdfVariables()">
<p>Page <span class="page"></span> of <span class="topage"></span></p>
<script>
function substitutePdfVariables() {
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.href);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
function substitute(name) {
var value = getParameterByName(name);
var elements = document.getElementsByClassName(name);
for (var i = 0; elements && i < elements.length; i++) {
elements[i].textContent = value;
}
}
['frompage', 'topage', 'page', 'webpage', 'section', 'subsection', 'subsubsection']
.forEach(function(param) {
substitute(param);
});
}
</script>
</body>
</html>
But this is probably not the right appoach because it would leak wkhtmltopdf into docfx.config and into the template system.
Current idea: using naming convention "header.html", "footer.html" in template to support header and footer. For example, following generates page header
<!DOCTYPE html>
<head>
<script>
function subst() {
var vars = {};
var query_strings_from_url = document.location.search.substring(1).split('&');
for (var query_string in query_strings_from_url) {
if (query_strings_from_url.hasOwnProperty(query_string)) {
var temp_var = query_strings_from_url[query_string].split('=', 2);
vars[temp_var[0]] = decodeURI(temp_var[1]);
}
}
var css_selector_classes = ['page', 'frompage', 'topage', 'webpage', 'section', 'subsection', 'date', 'isodate', 'time', 'title', 'doctitle', 'sitepage', 'sitepages'];
for (var css_class in css_selector_classes) {
if (css_selector_classes.hasOwnProperty(css_class)) {
var element = document.getElementsByClassName(css_selector_classes[css_class]);
for (var j = 0; j < element.length; ++j) {
element[j].textContent = vars[css_selector_classes[css_class]];
}
}
}
}
</script>
</head>
<body style="border:0; margin: 0;" onload="subst()">
<table style="border-bottom: 1px solid black; width: 100%">
<tr>
<td class="section"></td>
<td style="text-align:right">
Page <span class="page"></span> of <span class="topage"></span>
</td>
</tr>
</table>
</body>
</html>
Looks good to me. You just need to be aware that this kind of leaks wkhtmltopdf into the templating system of docfx.
Do you already have an idea how to solve the "TOC with pages numbers" request? It seems that wkhtmltopdf supports this. The flags --disable-dotted-lines and --xsl-style-sheet allow you to customize the TOC. For advanced scenarios the user should be able to customize the TOC. Maybe the default pdf template should already contain an xsl that will be used?
Note that adding headers and footers is _sort of supported_ using for example:
"wkhtmltopdf": {
"additionalArguments": "--footer-center [page] --footer-font-name Raleway"
}
in your docfx.json.
You can find details in the wkhtmltopdf documentation.
However I agree having something a little more flexible out of the box would be great.
I'm wondering what the best approach would be to support a header/footer that would apply to one or more specific pages?
Here are a couple example scenarios:
wkhtmltopdf doesn't currently seem to support these scenarios.
If we were to replace wkhtmltopdf with a different solution, and/or update docfx to support those scenarios, how could they be specified in docfx.json, and/or in the individual DFM pages?
I'm currently implementing a solution that can replace wkhtmltopdf.
Underneath, it uses Chromium to print to PDF.
If interested, see https://github.com/icnocop/htmltopdf.
One of the limitations is that the header/footer can't use JavaScript.
Here's an example of an HTML file whose content prevents displaying the footer:
https://github.com/icnocop/HtmlToPdf/blob/8e7209a84e56df57d510d4de7629fa0fae1d3deb/src/HtmlToPdfTests/FooterRightTests.cs#L200-L210
It uses the media attribute set to print which is similar to the @page CSS at-rule to indicate the style used when printing the file.
<style type="text/css" media="print">
#footer-template {display:none}
</style>
In this example, what's the best approach to be able to emit the style tag only for a specific DFM page, to be able to override styles that apply to all the other pages?
In my tests, when I specify a style tag in a DFM file, it gets stripped in the resulting HTML file.
_Edit_
Never mind, I figured out how to dynamically add a style tag using JavaScript in DFM:
<!-- Script to add style element -->
<script type="text/javascript">
/* Function to add style element */
function addStyle(styles) {
/* Create style document */
var css = document.createElement('style');
css.type = 'text/css';
if (css.styleSheet)
css.styleSheet.cssText = styles;
else
css.appendChild(document.createTextNode(styles));
/* Append style to the tag name */
document.getElementsByTagName("head")[0].appendChild(css);
}
/* Set the style */
var styles = '@page {margin-right: 0;}';
/* Function call */
window.onload = function() { addStyle(styles) };
</script>
Thank you.
Most helpful comment
Do you already have an idea how to solve the "TOC with pages numbers" request? It seems that wkhtmltopdf supports this. The flags
--disable-dotted-linesand--xsl-style-sheetallow you to customize the TOC. For advanced scenarios the user should be able to customize the TOC. Maybe the default pdf template should already contain an xsl that will be used?