How I Solved The Acrobat Popup Dialog/Action Dilemma
Out of frustration I created my own batch processing script that runs outside of the Actions Wizard.
In the last issue I talked about the Acrobat Action Wizard's missing feature that would allow a script to run before the documents are processed, or after the documents are processed, and how, out of frustration I created my own batch processing script that runs outside of the Actions Wizard. I needed to be able to run a script with a popup dialog for gathering information but only have this script appear once, at the beginning of the session. No matter how many ways I tried to accomplish this, through methods I had read about, or methods I came up with on my own, there were always extra easy-to-forget steps for the end user that would cause the action to malfunction if forgotten. The malfunction could be the popup dialog appearing for every PDF processed ("How do I stop this? Only 150 more popups to dismiss."), or not appearing at all.
There had to be a better way. I thought about this a lot. I needed a script that would open the dialog once, but also make sure it opened again the next time the action ran. And I needed to do this seamlessly without user interaction. It finally hit me one day and I'm happy to share it with you. But first I'm going to go through some of the methods I have used and the issues I have with them. I believe this is helpful for learning. Here's my list of methods:
1)Â Â The global variable test.
2)Â Â The number-of-PDFs field in a dialog.
3)Â Â The document creation method.
4)Â Â The ZZZ document.
5)Â Â My epiphany: The Timer - the method that makes all the others irrelevant.
Take the Acrobat Pro/JavaScript eLearning Course Acrobat Like a Pro
THE GLOBAL VARIABLE TEST
Pro: Easy script, works well.
Con: No way to delete global variable without user interaction. If the global variable is not deleted, the dialog will not run when the action is run again in the same session.
Method: The script tests for a global variable. If it is undefined, the dialog runs and also creates the global variable. When the script runs for the second document and each subsequent document, the global variable is not undefined, so the dialog does not run again.
Script:
/* I'm using an alert box instead of a dialog for testing and simplicity*/
if(global.myBatch==undefined)
{
if (app.alert("Do you want to continue this process?",2,2)==4)
{
/*The last parameter '2' in the alert box creates a yes/no buttons. Yes returns 4*/
global.myBatch="true";
}
else
{
event.rc=false;//stops action
this.closeDoc(true);//closes document
}
}
if (global.myBatch)
{
/*Shameless advertising script start*/
var oDoc=this;
var f=oDoc.addField("Decoy1","text",0,[0,792,612,792-2]);
f.fillColor=["RGB",0.635,0.016,0.031];
var f=oDoc.addField("Decoy2","text",0,[0,792-4,612,792-38]);
f.fillColor=["RGB",0.635,0.016,0.031];
f.alignment="center";
f.textFont="Helvetica-Bold";
f.textColor=color.white;
f.value="\x77\x77\x77\x2E\x70\x64\x66\x61\x75\x74\x6F\x6D\x61\x74\x69\x6F\x6E\x73\x74\x61\x74\x69\x6F\x6E\x2E\x63\x6F\x6D";
var f=oDoc.addField("Decoy3","text",0,[0,792-40,612,792-42]);
f.fillColor=["RGB",0.635,0.016,0.031];
oDoc.flattenPages();
/*Shameless advertising script end*/
}
To delete the global variable when the action is finished, run the following script in the console:
delete global.myBatch;
Download 25 test files and all five Action files
THE NUMBER-OF-PDFs FIELD IN THE DIALOG
Pro: User does not have to delete the global variable. It gets deleted automatically when the last file is processed.
Con: The user must count the number of files to be processed and remember to enter the number into the dialog field.
Method: The script tests for a global variable. If the global variable is undefined the dialog runs. One of the dialog fields is the number of PDFs in the folder that will be processed. The dialog creates a global variable which is the number of PDFs to be processed. The global variable number is decreased by 1 for each document. When the number reaches 0, the global variable is deleted.
Script:
/* I'm using a response box instead of a dialog for testing and simplicity*/
if(global.myBatch==undefined)
{
var rtn=app.response("Enter the number of PDFs:","www.pdfautomationstation.com",25);//25 is the default which is optional
if(rtn)
{global.myBatch=rtn}
else
{
event.rc=false;//stops Action
this.closeDoc(true);//closes PDF
}
}
if(global.myBatch)
{
global.myBatch--;//decreases by 1
/*Shameless advertising script start*/
var oDoc=this;
var f=oDoc.addField("Decoy1","text",0,[0,792,612,792-2]);
f.fillColor=["RGB",0.635,0.016,0.031];
var f=oDoc.addField("Decoy2","text",0,[0,792-4,612,792-38]);
f.fillColor=["RGB",0.635,0.016,0.031];
f.alignment="center";
f.textFont="Helvetica-Bold";
f.textColor=color.white;
f.value="\x77\x77\x77\x2E\x70\x64\x66\x61\x75\x74\x6F\x6D\x61\x74\x69\x6F\x6E\x73\x74\x61\x74\x69\x6F\x6E\x2E\x63\x6F\x6D";
var f=oDoc.addField("Decoy3","text",0,[0,792-40,612,792-42]);
f.fillColor=["RGB",0.635,0.016,0.031];
oDoc.flattenPages();
/*Shameless advertising script end*/
if(global.myBatch==0)
{
delete global.myBatch;
}
}
THE DOCUMENT CREATION METHOD
Pro: Easy to implement.
Con: User must manually delete the global variable. User must close the document that was created.
Method: The script tests for the number of active documents. If there's only one active document, the dialog runs and the script creates another document. If there's more than one active document, the dialog does not run. Since the document created will not be closed by the action, there should always be two active documents.
Note: In older versions of Acrobat, the Batch Process or Action, would not open the PDFs that were being processed. Somehow it would perform all the actions without actually opening the documents. I knew this for a couple of reasons. Firstly, you wouldn't see any of the documents open. Next, I would sometimes have documents with a document level script that popped up a message when the documents were opened. The messages would never pop up. You can't run an Action on documents like these now unless you want to dismiss a popup for every document because Acrobat now opens all the documents as the Action is running. You can see the documents opening and closing. I don't know when, or why, Acrobat started opening the documents during actions but in my opinion, performance was lost when they made this change. It takes a lot longer to process the same number of documents now. It takes time to open and close them. I wasn't sure if what I said in this paragraph was true, so I recently tested an Action with Acrobat X. Sure enough, the script had to be changed to test for zero active documents and only pop up the dialog if the number of active documents was 0 instead of 1.
Script:
/* I'm using an alert box instead of a dialog for testing and simplicity*/
if (app.activeDocs.length < 2)
{
if (app.alert("Do you want to continue this process?",2,2)==4)
{
app.newDoc();
}
else
{
event.rc=false;
this.closeDoc(true);
}
}
if(app.activeDocs.length>1)
{
/*Shameless advertising script start*/
var oDoc=this;
var f=oDoc.addField("Decoy1","text",0,[0,792,612,792-2]);
f.fillColor=["RGB",0.635,0.016,0.031];
var f=oDoc.addField("Decoy2","text",0,[0,792-4,612,792-38]);
f.fillColor=["RGB",0.635,0.016,0.031];
f.alignment="center";
f.textFont="Helvetica-Bold";
f.textColor=color.white;
f.value="\x77\x77\x77\x2E\x70\x64\x66\x61\x75\x74\x6F\x6D\x61\x74\x69\x6F\x6E\x73\x74\x61\x74\x69\x6F\x6E\x2E\x63\x6F\x6D";
var f=oDoc.addField("Decoy3","text",0,[0,792-40,612,792-42]);
f.fillColor=["RGB",0.635,0.016,0.031];
oDoc.flattenPages();
/*Shameless advertising script end*/
}
THE ZZZ DOCUMENT METHOD
Pro: Easy to implement.
Con: User can forget to include document in action folder. Some users might to have to add the document separately.
Method: A PDF with the file name ZZZ is added to the folder in which the action will be run. The files are usually processed alphabetically so ZZZ should be processed last. The script tests for a global variable. If the variable is undefined the script pops the dialog and creates the global variable. The script also tests the document file name. If the document file name is ZZZ the global variable is deleted, the action stops, and ZZZ is closed.
Until I had my latest epiphany in which this article is based, the ZZZ method was my favorite. As long as the user remember to copy the ZZZ file to the folder before starting the action, and as long as the action processed the file last, there were no issues. No need to close a file or manually delete a global variable. It was working well until a Mac user emailed me and said the ZZZ file was getting processed in random positions, not necessarily last. This was causing problems because as soon as the ZZZ file was opened for processing, the action would stop and the file would close. I have no idea how the order was selected on his Mac and no idea as to why it would be different from Windows, but this was my fourth method that now also ended up with an issue. I developed a quit workaround but it required another extra step now. The user would add a folder of files which excluded ZZZ to start the action, then add the ZZZ file separately. It would always end up at the end of the list. I needed another solution.
Script:
/* I'm using an alert box instead of a dialog for testing and simplicity*/
if (global.myBatch==undefined)
{
if (app.alert("Do you want to continue this process?",2,2)==4)
{
global.myBatch=true;
}
else
{
event.rc=false;
this.closeDoc(true);
}
}
if (global.myBatch)
{
if (this.documentFileName=="ZZZ.pdf")
{
event.rc=false;
this.closeDoc(true);
}
else
{
/*Shameless advertising script start*/
var oDoc=this;
var f=oDoc.addField("Decoy1","text",0,[0,792,612,792-2]);
f.fillColor=["RGB",0.635,0.016,0.031];
var f=oDoc.addField("Decoy2","text",0,[0,792-4,612,792-38]);
f.fillColor=["RGB",0.635,0.016,0.031];
f.alignment="center";
f.textFont="Helvetica-Bold";
f.textColor=color.white;
f.value="\x77\x77\x77\x2E\x70\x64\x66\x61\x75\x74\x6F\x6D\x61\x74\x69\x6F\x6E\x73\x74\x61\x74\x69\x6F\x6E\x2E\x63\x6F\x6D";
var f=oDoc.addField("Decoy3","text",0,[0,792-40,612,792-42]);
f.fillColor=["RGB",0.635,0.016,0.031];
oDoc.flattenPages();
/*Shameless advertising script end*/
}
}
MY EPIPHANY - THE TIMER
Since the ZZZ method was causing issues with some users, I couldn't stop thinking about how to develop another solution. Nothing I thought of would work because there was no way to "tell" the program to do something when the last document was processed, except by entering the number of documents into a popup dialog field. Then I had a thought.
What if I test for a global variable and when it returns undefined I pop the dialog then set the global variable as the current time? And what if change the global variable to the current time at the end of the script so it changes to the current time just before the document closes? And what if my test, for the when the variable is not undefined, is that the current time must be at least a set amount of time after the last change in the global variable? At first, I thought I was going to have to experiment with different time intervals and I thought, since different actions take different amounts of time to complete for each document, that I might have to adjust the time for different actions.Â
Not so. Because the last piece of the script is to set the variable to the current time, it wouldn't matter how long the action took per document. There would only be a split second between the end of the script and script restarting for the next document. My time interval had to be longer than the time between the script ending for one document and starting for next. It should also be short enough so that it would never be longer than the time between somebody running the action again. I tried 7,500 milliseconds (7.5 seconds) and it ran perfectly. The chances of somebody running the action again within 7.5 seconds was slim to none. And just none if I told them not to. I settled on ten seconds, just in case Acrobat stuttered in between documents in the action. My issue was finally solved. No extra steps for the user and no need to delete the global variable.
This was a game changer for me. A lot of automation projects I develop grab documents from different locations on the hard drive or network other than the action folder, save them to other locations other than the action folder, and connect to other files on the hard drive for importing data, inserting images, etc.Â
Because these projects are for outside organizations it is too inflexible and cumbersome to hard code the locations. It's a lot better to have a popup dialog at the beginning of the action for the user to browse the hard drive for a folder or file, and to enter information that might change when the action is run again. I will usually program the dialog to set the information as global variables, make them persistent (not lost when Acrobat is closed), and use those variables as the dialog defaults the next time the action runs. This way, if nothing changes, users don't have to enter the information each time. All they need to do is click OK on the dialog. But it is still flexible enough for them to easily change the dialog information. Now I don't have to worry about any extra steps for the end user. Everything just works.
I haven't got this far yet because this discovery is new for me, but I'm sure I'll be creating a dialog with radio buttons or a dropdown list of different actions so I can group multiple actions into one dialog, and simply call the corresponding folder level script when the dialog is dismissed.
Pro: Easy to implement. No extra steps for the end user. No need to delete a global variable or close a document.
Con: None
Script:
/* I'm using an alert box instead of a dialog for testing and simplicity*/
if (global.myTimer==undefined || new Date().getTime()>= Number(global.myTimer)+10000) /*10000 is ten seconds*/
{
if(app.alert("Do you want to continue this process?",2,2)==4)
{
global.myTimer=new Date().getTime();
}
else
{
event.rc=false;
this.closeDoc(true);
}
}
/*Shameless advertising script start*/
var oDoc=this;
var f=oDoc.addField("Decoy1","text",0,[0,792,612,792-2]);
f.fillColor=["RGB",0.635,0.016,0.031];
var f=oDoc.addField("Decoy2","text",0,[0,792-4,612,792-38]);
f.fillColor=["RGB",0.635,0.016,0.031];
f.alignment="center";
f.textFont="Helvetica-Bold";
f.textColor=color.white;
f.value="\x77\x77\x77\x2E\x70\x64\x66\x61\x75\x74\x6F\x6D\x61\x74\x69\x6F\x6E\x73\x74\x61\x74\x69\x6F\x6E\x2E\x63\x6F\x6D";
var f=oDoc.addField("Decoy3","text",0,[0,792-40,612,792-42]);
f.fillColor=["RGB",0.635,0.016,0.031];
oDoc.flattenPages();
/*Shameless advertising script end*/
global.myTimer=new Date().getTime();
See you soon…