PDF In-Depth

External Code for PDF Forms: The Secret Revealed

February 01, 2001

Advertisement
Advertisement
 

To summarize where we are, we've been trying to find a way to store functions as persistent globals, so that we can come back to them, from ANY future PDF form that our reader downloads from our site, and use the code that's stored there. It's kind of like being able to take a bathroom break during the Scholastic Aptitude Test, and having the Cliffs Notes to Euclid's Geometry already stored behind the toilet in the men's room. We want to be able to put whatever Cliffs Notes we want, behind whosoever's toilet we want.

Recap

What we've figured out so far is that we can convert a function to a string with JavaScript's built-in toString() function. And we can convert strings to functions with the built-in Function constructor. But in order to use the latter, we have to supply the "guts" of the function as a string, minus the declarative "function funcName(args)" prefix. We developed a regex to clip that prefix off of function declarations yesterday.

But we also have another problem to deal with, namely the problem that toString() introduces unwanted formatting into the strings it produces! Weirdly enough, it turns out that this function inserts newlines and spaces willy-nilly, to format our code, whether that's what we wanted or not. The reason this is a problem for us is that when we put the resulting string into a persistent global, and then that global gets read into memory again later (at the start of another session), the newlines cause errors of the "unterminated string literal" kind.

The answer to the latter problem is another regex. All we have to do is pass the output of toString() thru a regex that removes newlines. In JavaScript, we do:

str = str.replace(/\n/g,"");

This regex-replace operation is applied globally (because of the lowercase 'g') to all newlines. And since the replacement string is null, we end up deleting all newlines, plain and simple. Problem solved.

The Magic Formula

So, in order to store a library function as a persistent global, here is what we have to do:

  • Convert the function to a string.
    var str = myFunc().toString();
  • Take the declarative front end off.
    str = str.replace(/function [a-zA-Z_]+\(\S*\)/g,"");
  • Take the newlines out.
    str = str.replace(/\n/g,"");
  • Make it a global.
    global.f1 = str;
  • Make it persistent.
    global.setPersistent("f1",true);

To restore the function, we have to do this:

  • Read the global string into a variable (optional).
    var s = global.f1;
  • Construct a new function.
    var newFunc = new Function("a",s);
  • Use the new function just like you would the old one.
    x = newFunc( a );

The 'a' in the Function constructor is the argument that the old function took (if any). Some functions have multiple args, some have none; obviously you'll have to tailor this part to the situation, although I hasten to add that as an exercise, you should be able to devise a general solution (one set of code fitting all situations) using regexes, arrays, and/or common sense. We've already complicated this discussion enough with regexes, so I won't go there any more just now. However, I do encourage you to play with the above recipes for storing and reconstructing functions as persistent globals. Maybe you can find ways to improve on my scheme through the use of arrays, concatenated strings (join/slice methods), etc. In fact, I'm sure you can find many ways to improve on this scheme. All I was trying to do is determine a way in which persistent storage of library functions could be done. At all.

Checking to See If a Global Exists

Before I stop today, I want to give a tip for checking to see if a global already has been defined or already 'lives' because of persistence. Sometimes in JavaScript it is not easy to check a variable for validity. But in this case it turns out to be easy. You can check a global this way:

if (global.myWhatever == "undefined")   { // doesn't exist }else  
{ // exists} 

An undefined variable, in PDF JavaScript, will evaluate to the string "undefined". So testing it is easy. Use this trick to test whether your library functions (above) are present.

Another trick:

When you want to make a variable global, but not necessarily persistent, you do NOT have to store it in the Global object explicitly. Just go up to the Tools:Forms:Document JavaScripts menu command in Acrobat, and enter a global as you would a top-level function. (Delete the function skeleton.) For example, enter gMyVariable = 0; and hit OK to dismiss the dialog. (Don't type a function.) From that point on, gMyVariable will be globally available throughout your document, to any function that needs it. And, not only is it available throguhout the current document... it is available to ALL open PDF documents that have JavaScripts. As I said, it is a true global.

PDF In-Depth Free Product Trials Ubiquitous PDF

Debenu Quick PDF Library

Get products to market faster with this amazing PDF developer SDK. Over 900 functions and an equally...

Download free demo

Back to the past, 15 years ago! Open Publish 2002

Looking back to 2002, it's amazing how much of the prediction became a reality. Take a read and see what you think!

September 14, 2017
Platinum Sponsor





Search Planet PDF
more searching options...
Planet PDF Newsletter
Most Popular Articles
Featured Product

Debenu PDF Aerialist

The ultimate plug-in for Adobe Acrobat. Advanced splitting, merging, stamping, bookmarking, and link control. Take Acrobat to the next level.

Features

Adding a PDF Stamp Comment

OK, so you want to stamp your document. Maybe you need to give reviewers some advice about the document's status or sensitivity. This tip from author Ted Padova demonstrates how to add stamps with the Stamp Tool along with related comments.