Thursday, 28 January 2010

Friendly messages for Acrobat/Reader users who disable JavaScript

With the 9.3 update to Adobe Acrobat and Adobe Reader, if a user opens a PDF document with some JavaScript in it, and they have JavaScript disabled in their application preferences, they will see the Yellow Bar of Death:



While it's perfectly true that malicious JS code has been used in the past, the security holes that were exploited are now closed. 99.99999% of PDFs that use JS do so for perfectly safe and essential reasons, such as checking form fields and controlling multimedia - with JS disabled, a carefully-crafted PDF can be rendered useless.

The Yellow Bar of Death, in our opinion, somewhat overstates this security issue. Most people have no clue what JavaScript even is, so for a big scary banner to shout "Enabling JavaScript can lead to potential security issues" is going to send them scampering into trees unless the document jumps in and explains it in a calm, relaxing manner.

The solution, of course, is to use JavaScript to display that message - or rather to undisplay it. We add a layer or a page to the document that by default is shown when the PDF first opens, and then use a document-level script to hide it again. People with JS enabled see nothing, those with JS disabled see the message.

Method 1: Add a page

If we add an extra page to the document (at the start or end), we can set the document properties to open on that page by default (menu..file..properties..initial view... open to page) - this works even if JS is disabled. We then need to add a page-level script to that page, so our JS-enabled readers get automatically shunted to the REAL start of our document. Let's say for example that we had a 10-page file, added the calm explanation on page 11:

  • Open the pages sidebar and click once on page 11 to select it (it'll turn blue)
  • Click the options tool (the little gear wheel symbol on the sidebar) and choose "page properties"
  • Move to the Actions tab
  • On the "Page Open" event, choose "Run a JavaScript" and press ADD.
  • In the editor that appears, type this one line and press OK to close all the popups:
this.pageNum = 0;

  • ...that will send readers back to page zero, which is the JS equivalent of page 1. Do NOT use the "go to a a page view" action as this works even with JS disabled. We specifically want a JS action so it fails for the people we want to show our message to.
  • Save the PDF, and test it by disabling your JS (cmd-K or ctrl-K, JavaScript, untick the box)

Method 2: Add a layer

This works best for single-page documents but it's a bit fiddlier to apply. We're going to add a new OCG (layer), set it up to be visible and non-printing by default, then use a document-level script to hide it. As Acrobat has problems showing normal layers on top of Flash or 3D content, we need to borrow the services of the Watermarking tool to insert our layer, then use some JavaScript to rename it:

I'm assuming you have a suitable PDF to use as the message - if not, you can download ours by clicking this link. It's also easier if the PDF doesn't already have a watermark.
  • Open the base PDF and choose menu..Document..Watermark..Add
  • Before anything else, press "appearance options", and tick only the bottom two boxes.
  • Click OK and load your message from a PDF.
  • Set the position, opacity, scale etc as required
  • If the PDF has more than one page, press Page Range Options and set it to just the first page.
  • Click OK to create the layer.
At this point, the new layer is called "Watermark" and isn't visible on the layers sidebar. That may be fine, but if you want to add a real watermark, you'll need to rename this layer so you can control it separately. This requires a bit of scripting in the console window, but nothing too scary.

Open the console - cmd-J or ctrl-J, and press ENTER once to wake it up. Ignore the messages - press the trashcan to clear the window, and type or paste in this section of code:

var OCGs = this.getOCGs();
for (var i=0; OCGs && i<OCGs.length;i++) {
if (OCGs[i].name == "Watermark") OCGs[i].name = "JSMESSAGE";
}




Select it all, and press ctrl-enter or cmd-enter to run it. The result is the watermark is now in a layer called JSMESSAGE, so if you want to add a real watermark on top, you can. The layer still isn't shown in the sidebar, but that's fine - less to confuse our readers.

Now, we just need to add a document-level script that hides our JSMESSAGE layer when the document opens. Click Menu..Advanced..Document Processing..Document JavaScripts.

In the box, type some random name (e.g. "js message") and click ADD. In the editor window, delete everything and paste in the following code - almost the same as the one above, but this time we're setting the layer to be invisible:

var OCGs = this.getOCGs();
for (var i=0; OCGs && i<OCGs.length;i++) {
if (OCGs[i].name == "JSMESSAGE") OCGs[i].state = false;
}


Save the script and the PDF, and you can test your new message layer as for method 1 by disabling JS in General Preferences and re-opening the file.

Click here for an example of this message layer scripting - based on a file that contains our PDF Tube Flash wrapper and therefore contains a whole chunk of essential javaScript.