data-id=review-markup-and-approval

Review, Markup, and Approval

In this chapter you will learn how to make use of Acrobat’s ability to facilitate online collaborative reviews for many types of content. At the heart of this process is the set of commenting, markup, and approval tools available to the reviewers, and the tools available to the initiator for managing the review.

You can use JavaScript to customize the review process and how comments are handled, to add additional annotations, and to configure a SOAP-based online repository.

data-id=46929
data-id=working-with-comments-using-javascript

Working with comments using JavaScript

The Commenting toolbar provides reviewers with the tools necessary to create comments, which may be placed in the document in the form of notes, highlighting, and other markup. In this section, you are introduced to the various annotation types from the JavaScript point of view. In Getting annotation data you will learn how to extract content from comments and later, in Setting comment properties, you will learn to set the properties of a comment.

data-id=annotation-types

Annotation types

Each annotation has a JavaScript type. In the paragraphs that follow, the relation between each UI name and its corresponding type is delineated.

UI tool name
Type
Sticky Note tool
Text
Text Box tool
FreeText
Highlight Text tool
HighLight
Cross-Out Text tool
StrikeOut
Underline Text tool
Underline
Stamp tool
Stamp
Cloud tool. Polygon tool
Polygon
Arrow tool
Line
Rectangle tool
Square
Pencil Tool
Ink
Oval Tool
Circle
Attach a File as a Comment tool
FileAttachment
Record Audio Comment tool
Sound
Polygon Line tool
PolyLine
data-id=59776
data-id=getting-annotation-data

Getting annotation data

There are two methods for getting annotation information present in a document, or a collection of documents. These methods are getAnnot and getAnnots of the Doc object.

The getAnnot method returns an Annotation object, an object that holds all data of the annotation. This method takes two parameters, nPage (page number) and cName (the name of the annot). For example,

var a = this.getAnnot({ nPage: 2, cName: "myAnnot" });
if ( a != null ) {
    console.println("This annot has type " + a.type);
    if ( (a.type != "FileAttachment")  (a.type != "Sound") )
        console.println("The comment of this annot is " + a.contents);
}

When the user makes a comment using the UI, the name of the comment is randomly assigned. As a consequence, unless the annotation is created with the addAnnot method, in which the name of the annot can be assigned at the time of creation, the name is not typically known to the developer.

In normal workflows, the problem is to gather all comments in a document and process them in some way. The tool for doing this is getAnnots. The method returns an array of Annotation objects based on the search parameters, all of which are optional:

Additional discussion can be found in Sorting comments. See the JavaScript for Acrobat API Reference or full descriptions of these parameters.

The following code retrieves all annotations in the document, and sorts them by author name:

var annots = this.getAnnots({
    nSortBy: ANSB_Author
});
console.println("nAnnot Report for document: " + this.documentFileName);
if ( annots != null ) {
    console.show();
    console.println("Number of Annotations: " + annots.length);
    var msg = "    %s in a %s annot said: "%s"";
    for (var i = 0; i < annots.length; i++)
    console.println(util.printf(msg, annots[i].author, annots[i].type,
    annots[i].contents));
} else
    console.println("       No annotations in this document.");
data-id=83401

Adding comments with JavaScript

You can include a text box comment in a document and control its border, background color, alignment, font, and size characteristic. To create a Square type annotation, such as one created by the Rectangle tool in the UI, use the Document method addAnnot as follows:

this.addAnnot({
    page: 0,
    type: "Square",
    rect: [0,0,100,100],
    name: "OnMarketShare",
    author: "A.C. Robat",
    contents: "This section needs revision"
});

Refer to the Acrobat JavaScript API Reference for full descriptions of the properties specified above.

All annotations can be constructed in this way, in the case of sound and file attachment annotations, there is no JavaScript method for associating a recording with a sound annotation or a file with a file attachment.

data-id=32848
data-id=setting-comment-properties

Setting comment properties

To set the properties of a comment, create an object literal containing the properties to be applied to your comment. Then apply the properties to your annotation:

// Create the common properties in an object literal:
var myProps = {
    strokeColor: color.red,
    popupOpen: true,
    arrowBegin: "Diamond",
    arrowEnd: "OpenArrow"
};

// Assign the common properties to a previously created annot:
myAnnot.setProps(myProps);

The object literal, myProps, can be used again to change the properties of a collection of annotations, perhaps ones returned by the getAnnots, as discussed in Getting annotation data.

data-id=78613
data-id=online-collaboration-essentials

Online collaboration essentials

You can initiate several types of review workflows for PDF documents:

data-id=online-collaboration-essentials-topics

Online collaboration essentials topics

data-id=97742
data-id=reviewing-documents-with-additional-usage-rights

Reviewing documents with additional usage rights

For email-based reviews, the specification of additional usage rights within a document enables extra capabilities within Acrobat Reader. This enables the reviewer to add comments, import and export form-related content, save the document, or apply a digital signature.

For example, when using the Doc object encryptForRecipients method, you can specify the following permissions for reviewers:

The following code allows full and unrestricted access to the entire document for one set of users (importantUsers), and allows high quality printing for another set of users (otherUsers):

   var sh = security.getHandler("Adobe.PPKMS");
   var dir = sh.directories[0];
   var dc = dir.connect();
   dc.setOutputFields({oFields:["certificates","email"]});
   var importantUsers = dc.search({oParams:{lastName:"Smith"}});
   var otherUsers = dc.search({oParams:{lastName:"Jones"}});
   this.encryptForRecipients({
       oGroups:[
           {
               userEntities: importantUsers,
               permissions: { allowAll: true }
           },
           {
               userEntities: otherUsers,
               permissions: { allowPrinting: "highQuality" }
           }
       ],
       bMetaData: true
   });
   eMailList = "";
   for ( var i=0; i < importantUsers.length; i++)
       eMailList +=  (importantUsers[i].email + ",");
   for ( var i=0; i<otherUsers.length; i++)
       eMailList +=  (otherUsers[i].email + ",");
   // Now email the secured document.
   this.mailDoc({
       cTo: eMailList,
       cSubject: "For your eyes only",
       cMsg: "Please review for the meeting on Friday."
})
data-id=33983
data-id=emailing-pdf-documents

Emailing PDF documents

In addition to the email options available in the Acrobat menu and toolbar, it is also possible to use JavaScript to set up an automated email review workflow. This may be done through the Doc object mailDoc method. In the code shown below, the document is automatically sent to recipient@example.com :

this.mailDoc({
    bUI: false,
    cTo: "recipient@example.com",

    cSubject: "Review",
    cMsg: "Please review this document and return. Thank you."
});

Note

For Windows systems, the default mail program must be MAPI-enabled.

data-id=53029
data-id=javascript-based-collaboration-driver

JavaScript-based collaboration driver

JavaScript can be used to describe the workflow for a given document review, and can be used in review management. This is done by specifying a state model for the types of annotations a reviewer may use and creating an annotation store on the server for customized comment and review within browser-based workflows. The Collab object provides you with control over the possible states annotation objects may have, and may be used in conjunction with the SOAP object to create an annotation store.

There are several methods available within the Collab object that enable you to describe the state model for the review: these include addStateModel, getStateInModel, transitionToState, and removeStateModel.

The addStateModel method is used to add a new state model to Acrobat describing the possible states for an annot object using the model, and the removeStateModel method removes the model, though it does not affect previously created annot objects. Their usage is shown in the code below:

// Add a state model, this script can be placed at the folder level to
// install a custom state model for enterprise users, for example.
try{
    var myStates = new Object;
    myStates["initial"] = {cUIName: "Haven't reviewed it"};
    myStates["approved"] = {cUIName: "I approve"};
    myStates["rejected"] = {cUIName: "Forget it"};
    myStates["resubmit"] = {cUIName: "Make some changes"};
    Collab.addStateModel({
        cName: "ReviewStates",
        cUIName: "My Review",
        oStates: myStates,
        cDefault: "initial"
    });
}
catch(e){console.println(e);}

// Now transition all annots to the "rejected" state.
var myAnnots =              this.getAnnots( );
for ( var i=0; i<myAnnots.length; i++ )
    myAnnots[i].transitionToState("ReviewStates", "rejected");

// Now remove the state model.
try {Collab.removeStateModel("ReviewStates");}
catch(e){console.println(e);}

You can also use the SOAP object’s connect, request, and response methods to create customized commenting and review within browser-based workflows. You can do this by setting up a SOAP-based annotation store on the server using the Collab object’s addAnnotStore and setStoreSettings methods.

The Collab object’s addAnnotStore method requires three parameters:

The new Collab store class must contain the following definitions for the functions used to add, delete, update, and enumerate through the array of annotations:

The class SDKSampleSOAPAnnotStore, as shown in the sample code below, is defined in sdkSOAPCollabSample.js in the Acrobat SDK, and contains complete definitions of the three functions described above.

The sample code below provides a standard example of how to use the SOAP and Collab objects to customize your online collaborative review. Note that all of the reviewers must have a copy of the JavaScript collaboration store code. In Acrobat 7.0 and later, the Custom collaboration store type allows you to put the JavaScript on the server. The store type used is CUSTOM, and the setting is a URL to the JavaScript file:

// Here is the URL for a SOAP HTTP service:
var mySetting = "http://sampleSite/comments.asmx?WSDL";

// Here is the internal name for the collaborative store:
var myType = "mySOAPCollabSample";

// Set the connection settings for the SOAP collab store:
Collab.setStoreSettings(mySetting, myType);

// Set the default collab store:
Collab.defaultStore = myType;

// Add the collab store to the Acrobat Collab servers:
if (typeof SOAPFileSys == "undefined")
    Collab.addAnnotStore(
        myType,
        "SOAP Sample",
        {
            // Annot store instantiation function is required:
            create: function(doc, user, settings)
            {
                if (settings && settings != "")
                    return new SDKSampleSOAPAnnotStore(
                        doc, user, settings
                    );
                else
                    return null;
            }
        }
    );
data-id=93532

Spell-checking in comments and forms

You can check the spelling of any word using the spell object’ checkWord method. This can be applied to any form field or annotation. First retrieve the contents, and submit each word to the method.

data-id=setting-spelling-preferences

Setting spelling preferences

To set the dictionary order, first retrieve the array of dictionaries using the Doc object’s spellDictionaryOrder property. Then modify the order of the array entries, and assign the array to the same property. An array of currently available dictionaries can be obtained using the spell object’s dictionaryNames property.

To set the language order, perform a similar algorithm using the Doc object’s spellLanguageOrder property. An array of currently available dictionaries can be obtained using the spell object’s languages property.

data-id=adding-words-to-a-dictionary

Adding words to a dictionary

You can add words to a dictionary by invoking the spell object’s addWord method, as shown in the code sample below:

spell.addWord(myDictionary, "myNewWord");
data-id=31420

Approval

Approval workflows may include an automated process in which a PDF document is automatically sent via email to a recipient for their approval. For example, this may be accomplished through the usage of the Doc object’s mailDoc method. The user may then use a standard approval stamp, use a custom stamp, or use a Hanko stamp to create a secure digital signature.

data-id=63345
data-id=managing-comments

Managing comments

In this section, you will look in a more detailed way at the method of managing the comments in a document. The topics covered are:

data-id=39621
data-id=selecting-moving-and-deleting-comments

Selecting, moving, and deleting comments

Just as you can access the Comments List in the Acrobat user interface, you can likewise do so through using the syncAnnotScan and getAnnots methods of the Doc object. The syncAnnotScan method guarantees that all annotations in the document are scanned, and the getAnnots method returns a list of annotations satisfying specified criteria.

For example, the following code scans all the annotations on page 2 of the document and captures them all in the variable myAnnotList :

this.syncAnnotScan();
var myAnnotList = this.getAnnots({nPage: 1}); // Zero-based page number

To move a comment, use the corresponding setProps method of the Annotation object to specify a new location or page. To delete the comment, invoke the corresponding destroy method of the Annotation object. In the code sample below, all the free text comments on page 2 of the document are deleted:

for (var i=0; i<myAnnotList.length; i++)
    if (myAnnotList[i].type == "FreeText")
        myAnnotList[i].destroy();
data-id=13970
data-id=using-the-comments-list

Using the comments list

Once you have acquired the comments list through the syncAnnotScan and getAnnots methods of the Doc object, you can change their status, appearance, order, and visibility. In addition, you will be able to search for comments having certain characteristics.

data-id=70709
data-id=changing-the-status-of-comments

Changing the status of comments

To change the status of a comment, invoke the corresponding transitionToState method of the Annotation object, as shown in the code below:

// Transition myAnnot to the "approved" state:
myAnnot.transitionToState("ReviewStates", "approved");

The code above assumes myAnnot is an Annotation object of the document.

data-id=changing-the-appearance-of-comments

Changing the appearance of comments

You can change the appearance of a comment in a variety of ways. In general, the appearance of any comment may be changed by invoking the setProps method of the Annotation object, as shown in the code below:

myAnnot.setProps({
    page: 0,
    points: [[10,40], [200,200]],
    strokeColor: color.red,
    popupOpen: true,
    popupRect: [200,100,400,200],
    arrowBegin: "Diamond",
    arrowEnd: "OpenArrow"
});
data-id=33122
data-id=sorting-comments

Sorting comments

To sort comments, use getAnnots method of the Doc object and specify a value for the nSortBy parameter. Permissible values of nSortBy are

In addition, you can specify that the sorting be performed in reverse order by submitting the optional bReverse parameter to the method.

The code sample given below shows how to obtain a list of comments from page 2 of the document, sorted in reverse order by author:

this.syncAnnotScan();
var myAnnotList = this.getAnnots({
    nPage: 2,
    nSortBy: ANSB_Author,
    bReverse: true
});
data-id=showing-and-hiding-comments

Showing and hiding comments

To show or hide a comment, set its corresponding hidden property of the Annotation object. For example, the following code hides myAnnot :

myAnnot.hidden = true;
data-id=79147
data-id=exporting-and-importing-comments

Exporting and importing comments

To export all the comments in a file, invoke the exportAsFDF or exportAsXFDF methods of the Doc object. In both cases, set the bAnnotations parameter to true, as shown in the code sample below, which exports only the comments and nothing else:

this.exportAsFDF({bAnnotations: true});

To import comments from an FDF or XFDF into a file, invoke the importAnFDF or importAnXFDF methods of the Doc object.

data-id=68889
data-id=aggregating-comments-for-use-in-excel

Aggregating comments for use in Excel

The createDataObject method of the Doc object may be used to create a tab-delimited text file, which can then be used in Excel. To aggregate comments for use in Excel, collect all the comments using the getAnnots method, iterate through them and store them into a tab-delimited string, create a text file attachment object using the createDataObject method of the Doc object, pass the string to the cValue parameter in the createDataObject method, and optionally, save the attachment to the local hard drive using exportDataObject. Below is a sample script which follows the above outline:

var annots = this.getAnnots();
var cMyC = "NametPagetComment";
for ( var i=0; i<annots.length; i++ )
    cMyC += ("n"+annots[i].author + "t" + annots[i].page + "t""
        + annots[i].contents+""");

this.createDataObject({cName: "myCommentList.xls", cValue: cMyC});
this.exportDataObject({cName: "myCommentList.xls", nLaunch: 1});
data-id=69782
data-id=comparing-comments-in-two-pdf-documents

Comparing comments in two PDF documents

While the Acrobat user interface provides you with a menu choice for comparing two documents, it is possible to customize your comparisons using JavaScript. To gain access to multiple documents, invoke the app object’s openDoc method for each document you would like to analyze. Each Doc object exposes the contents of each document, such as an array of annotations. You can then compare and report any information using customized algorithms. For example, the code below reports how many annotations exist in the two documents:

var doc2 = app.openDoc("/C/secondDoc.pdf");
var annotsDoc1 = this.getAnnots();
var annotsDoc2 = doc2.getAnnots();
console.println("Doc 1: " + annotsDoc1.length + " annots.");
console.println("Doc 2: " + annotsDoc2.length + " annots.");

The above code will work if executed in the console. If executed from a non-privileged context, the secondDoc.pdf must be disclosed for app.openDoc to return its Doc object. Disclosed means that the code this.disclosed=true is executed when the document is opened, either as an open page action, or as part of a top level execution of document scripts. See the documentation of app.openDoc in the Acrobat JavaScript API Reference for details.

data-id=78138
data-id=extracting-comments-in-a-batch-process

Extracting comments in a batch process

In a batch process, you can open any number of Doc objects using the app object openDoc method. For each open document, you can invoke its corresponding Doc object getAnnots method to collect the comments in that file. If you would like to put all the comments together in one file, you can do so by creating a new document and saving the various arrays of comments into that new file.

The batch sequence samples include a sequence called Comments to Tab-Delimited File. This sequence uses the techniques described in the previous paragraph.

data-id=44729
data-id=approving-documents-using-stamps-japanese-workflows

Approving documents using stamps (Japanese workflows)

Approval workflows are similar to other email-based collaborative reviews, and provide you with the ability to set the order in which participants are contacted. This means that, based on the approval issued by a participant, the document can be mailed to the next participant, and an email can be sent to the initiator.

data-id=35058
data-id=setting-up-a-hanko-approval-workflow

Setting up a Hanko approval workflow

A registered Hanko is a stamp used in Japanese document workflows, and can be used to sign official contracts. Every registered hanko is unique and is considered a legal form of identification.

A personal Hanko is not registered, and is used for more common types of signatures, such as those used in meeting notes or budget proposals. Everyone in an organization who is involved in a document review must add their Hanko to the document in order for it to gain final approval.

Acrobat provides an assistant to help you set up an approval workflow. You can customize your workflow as well, by adding form fields to the document containing recipient lists to be chosen by the participant. This way, in case there are multiple directions for a given branch in the workflow, the participant may invoke automated functions that send the document to the correct participants, as well as an email to the initiator containing a record of activity.

You can use JavaScript to automate various steps within the workflow by sending the document and other information by email using the Doc.mailDoc method.

data-id=56222
data-id=participating-in-a-hanko-approval-workflow

Participating in a Hanko approval workflow

A participant receives an email with instructions for opening the document and completing their portion of the approval process. As noted above, this can be customized and automated through the use of form fields if the workflow is complex.

A Hanko stamp is a commenting tool used in approval workflows, and an Inkan stamp is a unique image that can represent an individual’s identity and can be used in place of a signature. Both are created, customized, and managed through the Acrobat user interface.

In order to use a Hanko or Inkan stamp, you will need to create a custom stamp and add digital signature information. Once the stamp has been created, you can apply it in your workflows.

data-id=installing-and-customizing-hanko-stamps

Installing and customizing Hanko stamps

Creating custom Hanko stamp information involves the combination of user information and a digital signature. Once you have set this up, it can be saved in a PDF file which is stored in the Stamps folder.

data-id=creating-custom-inkan-stamps

Creating custom Inkan stamps

To create an Inkan stamp, add your name, title, department, and company, choose a layout, and provide a name to use for the stamp. You can also import a PDF form to add customized features and additional fields containing personal information. In addition, it is possible to add secure digital signature information to an Inkan stamp.

data-id=deleting-custom-stamps

Deleting custom stamps

You can delete any Hanko and Inkan stamps that you created, though it is not possible to delete any of the predefined stamps in the Stamps palette.