Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Safari non-blocking window.print

I have a specific problem with page printing in JavaScript. I need to open my page on another tab with all scripts removed (this way: $(document).get(0).documentElement.innerHTML.replace(/<script[^>]+>.*?<\/script>/gi, '') and then call window.print() inside new tab, and close it afterwards.

That's because errors in scripts are causing problems with printing. Code responsible for the whole printing:

var w = window.open();
w.document.write(
  $(document).get(0).documentElement.innerHTML.replace(/<script[^>]+>.*?<\/script>/gi,'')
);
w.document.close();

var loadingImagesInterval = setInterval(function() {
  var imgs = w.document.querySelectorAll('img');
  for (var i = 0; i < imgs.length; i++) {
    if (!imgs[i].complete) return;
  }

  clearInterval(loadingImagesInterval);

  w.focus();
  w.print();
  w.close();
}, 100);

Basically, the problem is, on iOS, w.print() seems not to block code execution until confirm/cancel in printing view and w.close() is called immediately after. All other browsers work just fine: Mac Chrome, Mac Safari, IE11, Mac Firefox. All fine. Just not iOS Safari.

I tried this code, but didn't work as well:

w.matchMedia('print').addListener(function(mql) {
  if (!mql.matches) {
    w.close();
  }
})

Is there a better way to deal with my problem?

like image 202
Tomasz Kasperek Avatar asked Feb 14 '17 10:02

Tomasz Kasperek


1 Answers

EDIT: iOS version 12.2 introduced a "Done" button when opening a page from the Home Screen, so there is no need for a CLOSE button as described below. It is only needed for 12.0 and lower.

I worked around this by:

  • detecting Safari;
  • adding print and close buttons and hiding them for the print;
  • avoiding write() because it opens a new page, and the close button will not return the user to the previous page.

Caveat:

  • the popup blocker might have to be deactivated in Safari's settings to prevent the alert "This website has been blocked form automaticaly printing."
// detect Safari
if (navigator.userAgent.indexOf("Safari") !== -1) {
  // make print button
  const print_button = document.createElement('button');
  const print_button_text = document.createTextNode("Print");
  print_button.appendChild(print_button_text);
  print_button.addEventListener(
    "click",
    function() {
      // hide the buttons before printing
      print_button.style.display = 'none';
      close_button.style.display = 'none';
      newWindow.print();
      // delay reappearing of the buttons to prevent them from showing on the print
      setTimeout(() => {
        print_button.style.display = 'block';
        close_button.style.display = 'block';
      }, 2000);
    },
    false
  );
  // make close button
  const close_button = document.createElement('button');
  const close_button_text = document.createTextNode('Close');
  close_button.appendChild(close_button_text);
  close_button.addEventListener(
    "click",
    function() {
      newWindow.close();
    },
    false
  );
  newWindow.document.body.appendChild(print_button);
  newWindow.document.body.appendChild(close_button);
};

And then I added the content I wanted to print. I hope this helps.

like image 160
skinnedpanda Avatar answered Sep 29 '22 10:09

skinnedpanda