0

I have a HTML page with a table on it (attached to this)

I am trying to hide one of the columns at runtime. I know the JS is firing as I am outputting some text to the page and thats working (see div id poo)

https://pastebin.com/iqMnYGgu <-- html here

If I open the page in a browser, the JS works as expected, but for some reason the wkhtmltopdf binary doesn't seem to like it

Wonder if its a problem with qt but how do I test that?

The wkhtmtopdf command line I am using is:

# wkhtmltopdf-amd64 \
   --encoding UTF-8 \
   --margin-top 10 \
   --margin-right 10 \
   --margin-bottom 25 \
   --margin-left 10 \
   --page-size A4 \
   --orientation portrait \
   --dpi 300 \
   --zoom 0.9 \
   --header-spacing 30 \
   --no-outline \
   --no-stop-slow-scripts \
   --disable-smart-shrinking \
   --javascript-delay 5000 \
   --debug-javascript /tmp_wkhtmlto_pdf_XlMAtk.html \
   output.pdf

Any advise on how to debug this?

I've stayed away from jquery and have gone for vanilla JS which I thought would be better for all concerned.

Here is a visual description of the issue:

enter image description here

yunzen
  • 32,854
  • 11
  • 73
  • 106
Chris
  • 546
  • 1
  • 4
  • 18
  • There seem to be some extra closing `div` tags. That might be the crucial point here – yunzen Dec 01 '22 at 10:08
  • See https://ctrl.vi/i/YOD3qFHs4 for details – yunzen Dec 01 '22 at 10:12
  • Its not that. They are simply left over from when I anonymised the real page for this post. – Chris Dec 01 '22 at 10:12
  • I've removed those, and same issue – Chris Dec 01 '22 at 10:14
  • What does you debugging output tell you (you gave the command line parameter `--debug-javascript /tmp_wkhtmlto_pdf_XlMAtk.html` )? – yunzen Dec 01 '22 at 10:17
  • I pasted your code to a codepen. https://codepen.io/yunzen/pen/VwdELZV/3efaca2f58235cc40e46859e5ff1a75d. The JS code doesn't work there either – yunzen Dec 01 '22 at 10:22
  • Your attribute quotes are weird. Sometimes you have something like this `` – yunzen Dec 01 '22 at 10:24
  • The js works in the codepen. It only has to hide the totals. Which it has done, but it should also remove the total - which it used to do before I started debugging\ – Chris Dec 01 '22 at 11:27
  • The JS does not work WITHOUT ERROR. Look at the console log! – yunzen Dec 01 '22 at 12:40
  • Does this help? https://stackoverflow.com/questions/17151755/debugging-javascript-in-wkhtmltopdf – yunzen Dec 01 '22 at 13:16
  • It seems as if the QtWeb Browser, which does the browsing part behind the scenes in wkhtmltopdf, doesn't support removing HTMLElements with the `remove` method (I got no reference for this, but this stems from testing). Try replacing every `.remove()` with `.outerHTML = ""` – yunzen Dec 01 '22 at 13:58
  • Or use the polyfill from here: https://github.com/chenzhenxi/element-remove/blob/master/index.js – yunzen Dec 01 '22 at 14:03

2 Answers2

1

I think your issue is related to the very old (2013) browser which is the behind-the-scenes HTML/CSS/JS-Interpreter of wkhtmltopdf. This browser is the QtWeb browser, which last update dates from September 2013. The QtWeb browser uses the AppleWebKit 534.34 engine, which dates back to 2011.

The support for Element.remove() in Safari browsers seems to have only been integrated as soon as October 2013.

Therefore it is save to assume there is no support for Element.remove() in wkhtmltopdf.

You have several alternatives at hand.

  1. Use targetElement.outerHTML = '' instead of targetElement.remove()
  2. Use targetElement.parentElement.removeChild(targetElement) instead of targetElement.remove()
  3. Keep using targetElement.remove(), but insert this polyfill before
(function (arr) {
  arr.forEach(function (item) {
    if (item.hasOwnProperty('remove')) {
      return;
    }
    Object.defineProperty(item, 'remove', {
      configurable: true,
      enumerable: true,
      writable: true,
      value: function remove() {
        this.parentNode && this.parentNode.removeChild(this);
      }
    });
  });
})([Element.prototype, CharacterData.prototype, DocumentType.prototype].filter(Boolean));

yunzen
  • 32,854
  • 11
  • 73
  • 106
0

Try follwing JS code:

I added an assertion that the respective targetElement exists before trying to remove it.

if (targetElements) {
   // ...
}
function sortOutTotals() {
  document.getElementById("poo").textContent = "something here";
  var masterElement = document.getElementsByClassName(
    "ceta_row_quote_section_detail"
  );

  for (var i = 0; i < masterElement.length; i++) {
    var subElement = masterElement[i];
    var targetElement = subElement.querySelector("td[data-col='quotedtotal']");
    console.log(targetElement.textContent);
    if (targetElement) {
      targetElement.remove();
      targetElement.textContent = "poo";
    }
  }

  var masterElement = document.getElementsByClassName(
    "ceta_row_quote_section_detail"
  );
  for (var i = 0; i < masterElement.length; i++) {
    var subElement = masterElement[i];
    var targetElement = subElement.querySelector("td[data-col='description']");
    if (targetElement) {
      targetElement.colSpan = 2;
    }
  }

  var masterElement = document.getElementsByClassName(
    "ceta_row_quote_column_headings"
  );
  for (var i = 0; i < masterElement.length; i++) {
    var subElement = masterElement[i];
    var targetElement = subElement.querySelector("th[data-col='quotedtotal']");
    if (targetElement) {
      targetElement.remove();
    }
  }

  var masterElement = document.getElementsByClassName(
    "ceta_row_quote_column_headings"
  );
  for (var i = 0; i < masterElement.length; i++) {
    var subElement = masterElement[i];
    var targetElement = subElement.querySelector("th[data-col='description']");
    if (targetElement) {
      targetElement.colSpan = 2;
    }
  }
}

window.onload = function (e) {
  setTimeout(function () {
    sortOutTotals();
  }, 10000);
};

Also you have got some flaws in your HTML code. Some attributes are wrong and you have extra whitespace in some data-col attributes, which is not automatically accounted for in JS.

For example:
This:
<th class='ceta_cell_heading ceta_data_type_text'' data-col=' description'>Description</th>
Should be:
<th class='ceta_cell_heading ceta_data_type_text' data-col='description'>Description</th>
------------------------------------------------^----------^

If you are not able the format the data-col values without the whitespace try to change the selector query code from "th[data-col='quotedtotal']" to "th[data-col*='quotedtotal']" (added the asterisk * before the equals sign)

yunzen
  • 32,854
  • 11
  • 73
  • 106
  • Good spot on the data attributes. I fixed that and added the assertion, but it didn't help. I'm not sure how the assertion would help me, but I willing to try anything at the moment – Chris Dec 01 '22 at 11:23