Creating a Flip Book CQ Component

The canvas element is a new tag included in HTML 5. This allows for dynamic renderings of 2D shapes and bitmap images. I recently stumbled across a great example of the powerful effects that can be accomplished with the canvas element and javascript on a web app called 20 Things I learned about Browsers and the Web. The web application tells a nice summary of the basic history of the internet and open web technologies. What really makes it cool is that the information is presented as an interactive book and allows the user to “flip” the pages by dragging the mouse.

I thought it would be interesting to take this functionality and create a re-usable component in CQ. This would allow authors to add the component onto any paragraph system and drag text and images from the content finder to populate the “pages” of the book. The following tutorial focuses on creating a custom CQ component that uses its own CSS, images, and Javascript to make it run.

Continue reading…

Populate a Drop Down List in LiveCycle Designer with Dynamically Generated XML

One way to populate a Drop-down List on a LiveCycle form is using XML binding. In the situation explained below, the XML document is dynamically generated and bound to the form’s data model within a LiveCycle process by querying the database.

Situation:

Querying a database for all the supervisors and their ID. Then populate a drop-down list on the form with a single Data Connection.

4 Steps:

  1. Create a DataConnection on your form with an XSD that includes unbound occurrence of the list items.
  2. Add a Drop-down list to the form
  3. Bind the data to the drop-down list
  4. Create an Action Profile process to pre-populate the form with data from the database

1. Create a DataConnection on your form with an XSD that includes unbound occurrence of the list items.

Since the drop down list is only one field in the form and we are using a single data connection to bind data to the form, insert the following element node for the Supervisor Drop-down List. The selected fields are to be used to hold the currently selected value in the drop-down list.

<xs:element name="supervisorList">
      <xs:complexType>
              <xs:sequence>
                   <xs:element name="supervisor">
                         <xs:complexType>
                             <xs:sequence maxOccurs="unbounded">
                                 <xs:element name="supervisorID" type="xs:int"/>
                                 <xs:element name="supervisorName" type="xs:string"/>
                             </xs:sequence>
                         <xs:complexType>
                     </xs:element>
              </xs:sequence>
       </xs:complexType>
 </xs:element>
<xs:element name="selectedSupervisorName" type="xs:string"/>
<xs:element name="selectedSupervisorID" type="xs:int"/>

To add the Data Connection to your form:

  • Right click on the Data View Tab
  • Select New Data Connection
  • Select XML Schema
  • Browse to the XSD in your Application
  • Select the root node and Press OK

2. Add a Drop-down list to the form

From the Object Library in LiveCycle Designer, drag the Drop-down List object on to the form.

3. Bind the data to the drop-down list

Under the Object Panel, click on the Binding Tab. Bind the item to the selectSupervisorID in the Data Connection.

After adding data binding, the Specify Item Values text should become a green hyperlink. If link text is not green, ensure that dynamic properties is turned on. Click on the Specify Items Value.

Fill out the fields as shown above. Notice the [x] in the Items field. This enables all the elements to be loaded in to the list.

4. Create an Action Profile process to pre-populate the form with data from the database

In order to pre-populate the Drop-down list before the user sees the form:

  1. Create an Action Profile for the form that will call a Prepare Data Process
  2. Inside the Prepare Data Process, Create an XML variable called SupervisorList
  3. Inside the Prepare Data Process, Query the Database and Build an XML Variable using the Service Query for Multiple Rows as XML Service (Foundation/JdbcService).  After applying a SQL Statement to retreive the Supervisor ID and Supervisor Name from the database, click on the elipses button next to XML Information and fill it according to the image below according to your XSD.
  4. Set the Output for Step 3 Service to be the XML Variable created in Step 2.
  5. Bind the XML to the XSD element used in the forms DataConnection using setValue

Now, when the user pulls up the form in Workspace, it comes pre-populated with all of the Supervisors Names. The value for each field will be the Supervisor ID in this case.

Compiling a PDF Portfolio in LiveCycle

Situation:

How to merge multiple PDFs (retreived from a Database BLOB) and compile them using DDX and LiveCycle (ADEP). The portfolio will build based on the number of documents stored inside the database.

In this situation we will be compiling a Cover Page, Content Document(s), and a Final Document. Depending on the workflow state, there could be 0-5 documents in the database under the Content Document(s) section. The process is flexible enough to handle this.

Create the DDX File:

  1. Start by looking at the Assembly Descriptor documentation and DDX Reference Guide.
  2. In Workbench: Create a New Application (File>New>Application)
  3. Inside the Application directory, create a new folder and name it Assets.
  4. Locate the Acrobat .nav File you want to use. It will be located on your filesystem here: [Acrobat Location]\Acrobat\Navigators. For this situation AdobeRevolve.nav is being used. Import the .nav file into your Application’s Assets folder.
  5. Create a DDX file
    1. Right Click on Asset Folder> New > Assembly Descriptor.
    2. Provide a name for the DDX document.
    3. Click Finish.
    4. The Document Builder Window should come up inside Workbench
  6. The DDX File in the End will look like this:
    1. Start by Selecting New Result>PDF and Name it CompiledPDF
    2. Drag the Portfolio Component Under the CompiledPDF
    3. Under the Portfolio Editor paste the following elements:
      <Portfolio>
        <ColorScheme scheme="darkblueScheme"/>
        <Header/>
        <WelcomePage/>
        <Schema/>
        <DisplayOrder/>
        <SortOrder/>
        <Navigator source="AdobeRevolve.nav"/>
      </Portfolio>
    4. Press Apply in the Editor
    5. Drag the Navigator icon under the Portfolio Icon
    6. Paste the following under the Navigator Editor:  <Navigator source=”AdobeRevolve.nav”/>
    7. Press Apply in the Editor
    8. Drag the Packaged Files Icon underneath the Portfolio Icon
    9. Then add Seven PDF Documents sources under the Packaged Files and Name them in their Source field accordingly
    10. For Only the CoverPage document (the first one), go under the Basic tab and select both “This is the Base Document” and “There must be at least one valid source in this document” and ensure both of these boxes are deselected for the other PDF Document.
  7. Validate the DDX and Save it

Create a Process that will retrieve the documents from the database BLOB, assign them to a document map, invoke the DDX, Output a single PDF Portfolio document

The process will be built to look something like this:

In this process you will need the following variables:

    • thePortfolio–document–Output–Required
    • retrievedDocument –document
    • mapPortfolioDocs–map <document>
    • totalContentDocs–int
    • counter–int
    • tempContentDocID– string
    • PortfolioAssemblerResult–AssemblerResult
Retrieve a specific PDF document from the Oracle database BLOB and store it in the local variable retrievedDocument by executing the following executeScript service.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import javax.sql.DataSource;
import javax.naming.InitialContext;
 try {
   InitialContext context = new InitialContext();
   String queryQuery = [input your query here to get blob]
   //If you need to pass a process variable use "patExecContext.getProcessDataValue("/process_data/@counter");
   try {
    DataSource ds = (DataSource) context.lookup("java:/DDXDocs_DS");
    connection = ds.getConnection();
    queryStatement = connection.prepareStatement(queryQuery);
    results = queryStatement.executeQuery();
    if (results.next()) {
        java.sql.Blob documentBlob = results.getBlob(1);
        com.adobe.idp.Document document = new com.adobe.idp.Document(documentBlob.getBinaryStream());|
        patExecContext.setProcessDataValue("/process_data/@retrievedDocument", document);
     }
   }catch(Exception ex){
	System.out.println(ex.printStackTrace());
} finally {
    if (results != null) {
    	 results.close();
    }
    if (queryStatement != null) {
        queryStatement.close();
    }
    if (connection != null) {
        connection.close();
    }
   }
 } catch (Exception e) {
   e.printStackTrace();
 }

 

To test if a BLOB had been retrieved use the following route condition:

getDocLength(/process_data/@retrievedDocument)==0

 

If the document  was successfully retrieved, map it to the map <document> variable (mapPortfolioDocs) based on the id you gave it in the DDX source, using the setValue mapping below:

After retrieving all of the documents available, it is time to InvokeDDX. Using the Invoke DDX Service:
Finally, using the setValue operation, map the AssemblerResult to the output document variable (thePortfolio):

 

Configuring Watched Folder for PDF Generator

To configure a watched folder in the Admin Console for PDF Generator:

  1. Create a folder to be your watched folder on your filesystem
  2. Login to the ADEP Admin Console (http://[servername]:[portnumber]/adminui/)
  3. Navigate to Services > PDF Generator
  4. Click On Sources
  5. Category=PDF Generator, Click Filter
  6. Click on ‘GeneratePDFService: 1.0 ‘ [Documentation on GeneratePDFService]
  7. In the ‘End Points’ tab, choose ‘WatchedFolder’ from the dropdownlist
  8. Click ‘Add’ (Resource: Description of Watched Folder End Point properties)
  9. For ‘Description’, type something to the effect of “Watched Folder Endpoint PDFG”
  10. In ‘Enter path for the watched folder’, type in the fully qualified path to the folder you created in Step 1
  11. In the Operation Field, select CreatePDF2 from dropdown
  12. In the ‘Input Parameter Mappings’ section, for the ‘inputDocument’ field, select variable, type *.* (this will allow all supported input type files)
  13. In the ‘Output Parameter Mappings’ section, for the ‘Output PDF Document’ field, type %F%E.pdf (this will inherit the input filename and extension and append the .pdf extension.
  14. Click the Add button to save the changes.
  15. Navigate to the Watched Folder you created in Step 1, you should now see new directories: /input, /result, /staged, /failed, /preserve
  16. Test by copying a Word document to the /input folder. It should disappear a few seconds later
  17. If successful, the generated PDF will appear in /result directory. If it failed, the document and reason for failure appear in the /failed directory

Making LiveCycle Workspace Tasks Only Visible to Specific Users/Groups

If you want to make a Workspace task only visible to specific groups, you have to specify who can Invoke the task through the AdminUI.

Prior to setting this up, be sure that you have already set up the groups you will need in order to lock down tasks to specific users and groups. Also be sure that all the users that need to invoke processes through workspace are given the Workspace User Role.

  1. Login into Admin Console http[s]://[server]:[port]/adminui
  2. Services>Applications and Services>Service Management
  3. Click the category dropdown, choose the category your process belongs to, and click filter.
  4. Locate the Process you wish to lock down and click the name of theProcess
  5. Click security tab
  6. Click Add Principal
  7. Choose User/Group in the “In” dropdown and click filter
  8. Click on User or Group you wish to add
  9. Check INVOKE_PERM
  10. Click Add
  11. Test by logging into Workspace as a user that should be able to invoke a task, task card should be visible.
  12. Then log into Workspace as a user that should not be able to invoke a task, the task card should not be visible.

Repeat steps 6-10 for each user/group
Repeat steps 4-10 for each process

Note: If a user has the Contentspace User or an Administrator role, they may be able invoke most tasks

Required Digital Signatures in LiveCycle form

Description:
Recently, I had a project in which a form was being routed to three people in a serial fashion. However, prior to submitting the form we wanted to test whether the current user had signed the form in his/her designated spot. In order for the digital signatures to remain valid we could not make adjustments to the XML Schema and then use the RenderForm activity in LiveCycle– signatures would have been broken. So we had to put all the code to handle this in the form.

Situation:
There are three roles, Employee, Supervisor, and Reviewer. The form is routed through a LiveCycle process in that order. The Supervisor and Reviewer can either Approve or Decline the form. If the form is Declined it gets routed back to the Employee.

Setting up the form:

  • Add a Text Field, name it requiredSignature, and set its presence to Invisible and set its value to “Employee”
  • Add 3 digital signature fields and named them: employeeSignature, supervisorSignature, and reviewerSignature
  • Put the Approve/Decline option as a drop-down list into the form instead of in Workspace User Action so we did not have to depend on the AWS_ACTION drop down and Form Bridge because we are submitting as a PDF due to the digital signatures, everything is self-contained in the form.
  • The bottom of the form looks like this:

    Three Digital Signatures

    Three Digital Signatures

 

Code:

Three things you should know about the following code:

  1. signatureValidate returns:
    -1 — Not a signature field
    0 — Signature is blank
    1 — Unknown status
    2 — Signature is invalid
    3 — Signature of document is valid, identity of signer could not be verified
    4 — Signature of document is valid and identity of signer is valid.
  2. event.target.getField() you must include [0] in order target the designated field.
  3. [signatureField].mandatory makes that signatureField required prior to submit; [signatureField].disabled makes that signatureField no longer required in order to submit the form.

To be placed on the in the preSubmit Event for the form:

if (requiredSignature.rawValue==”Employee”){

var oState = event.target.getField(“employeeSignature[0]“).signatureValidate();

if (oState > 3){

employeeSignature.mandatory = “disabled”;
requiredSignature.rawValue=”Supervisor”;

}
else{

employeeSignature.mandatory = “error”;

}

}

else if (requiredSignature.rawValue==”Supervisor”){

var oState = event.target.getField(“supervisorSignature[0]“).signatureValidate();

if (oState > 3){

supervisorSignature.mandatory = “disabled”;
requiredSignature.rawValue=”Reviewer”;

}
else{

supervisorSignature.mandatory = “error”;

}

}else if(requiredSignature.rawValue==”Reviewer”){

var oState = event.target.getField(“reviewerSignature[0]“).signatureValidate();
if (oState > 3){

reviewerSignature.mandatory = “disabled”;

}

else{

reviewerSignature.mandatory = “error”;

}

}

else if(requiredSignature.rawValue==”Decline”){

requiredSignature.rawValue=”Employee”;

}

 

On the Supervisor Approve/Decline Drop-down list add the following code to the exit Event:

var oState = event.target.getField(employeeSignature[0]“).signatureValidate();

if(this.rawValue == “Approve”){

if (requiredSignature.rawValue==”Supervisor”){
//do nothing


}

else if(requiredSignature.rawValue==”Decline”){

requiredSignature.rawValue=”Supervisor”;

if (oState > 3){

supervisorSignature.mandatory = “error”;

}

supervisorSignature.presence = “visible”;
supervisorSignatureDate.presence = “visible”;

}

}

else{

if (requiredSignature.rawValue==”Supervisor”){

if (oState > 3)
{

requiredSignature.rawValue=”Decline”;

}
supervisorSignature.mandatory = “disabled”;

}

supervisorSignature.presence = “hidden”;
supervisorSignatureDate.presence = “hidden”;

}

 

Result:

If an Employee attempts to Submit the form without signing the form, he/she will get the following Error Message:

Employee Signature Error Message

Employee Signature Error Message

Silent Print in Acrobat Using JavaScript

I received a question from a customer on whether or not it is possible to create a toolbar button that will perform a silent print in Acrobat.  Well, it turns out that using JavaScript it is possible and really isn’t all that difficult.

Here’s some code:

    
    // if the application is Adobe Acrobat...
    //then create the silent print button
    if(app.viewerType == "Exchange-Pro") {

        app.trustedFunction(customSilentPrint);

        app.addToolButton({
            cName: "customSilentPrint",
            cExec: "customSilentPrint()",
            cTooltext: "Print Silent",
            cLabel: "Print Silent",
            cEnable: "event.rc = (app.doc != null)" });
        }

    function customSilentPrint(){

        // explicitly raise privileges
        app.beginPriv();

        try{
            // get the printer params
            var pp = this.getPrintParams();

            // don't show the print dialog window
            pp.interactive = pp.constants.interactionLevel.silent;
        }
        catch(err){
            app.alert("Error setting up printing parameters.\n\n" + err);
        }

        try{
            this.print(pp);
        }
        catch(err){
            app.alert("Error Printing.\n\n" + err);
        }

        // end explicit privileges
        app.endPriv();
    }



As you can see, there really isn’t much to this code, but let’s break it down.

First we check to ensure we are in Acrobat and, if so, we add the button called “Print Silent” to the Acrobat toolbar:

    // if the application is Adobe Acrobat...then create the silent print button
    if(app.viewerType == "Exchange-Pro") {

        app.trustedFunction(customSilentPrint);

        app.addToolButton({
            cName: "customSilentPrint",
            cExec: "customSilentPrint()",
            cTooltext: "Print Silent",
            cLabel: "Print Silent",
            cEnable: "event.rc = (app.doc != null)" });
    }


Next we create the function called customSilentPrint and raise privileges:

    function customSilentPrint(){

        // explicitly raise privileges
        app.beginPriv();


Within the function we get to the meat of the work by creating a print params object and setting the interactionLevel to silent.

        try{
            // get the printer params
            var pp = this.getPrintParams();
        
            // don't show the print dialog window
            pp.interactive = pp.constants.interactionLevel.silent;
        }


Now that we are set up to print silent, call the print function with these lines:

        try{
            this.print(pp);
        }
        catch(err){
            app.alert("Error Printing.\n\n" + err);
        }


To finish off our code we lower our privileges and close out the function:

        // end explicit privileges
        app.endPriv();

    }


As you can see there’s really no magic here, but this JavaScript code is a nifty little way to print silently in Acrobat.

Also, I haven’t researched silent printing using reader, but if you have tried it and succeeded or failed, please feel free to add to the post via comments.

BTW – If you don’t know how to create a toolbar button or install JavaScript in Acrobat, check out my collegue Venkata’s post here.

RIAs and Mobile Solutions to the Warfighter – Webinar on September 9

ISS and Adobe are partnering to offer a free webinar on RIAs in the US Department of Defense. The title is “Information to the Edge – RIAs and Mobile Solutions for the Warfighter”.

It’s September 9th at 2 PM EST. More details are here http://www.adobegovernmentevents.com/UsingRIAs/registration.html

You can register here http://www.adobegovernmentevents.com/UsingRIAs/registration.html

Motorola and Verizon announce DROID 2 with Flash Player 10.1 preinstalled

Motorola and Verizon announce pre-sale of DROID 2 by Motorola starts Aug 11 with Android 2.2 and Adobe Flash Player 10.1 preinstalled.
DROID 2 is a feature-packed device that helps manage work and social life with an enhanced QWERTY keyboard, increased processing power, ultra high-speed Web browsing, 3G Mobile HotSpot capabilities, full push corporate e-mail, intuitive social messaging and Adobe® Flash® Player 10.1 for access to the full web on the go – all built on Android 2.2.  Flash Player 10.1 lets mobile users experience millions of websites the way they were meant to be seen – with rich Internet applications (RIAs), content inside the browser, including games, animations, data presentations and visualizations, e-commerce, music, video, audio and more. DROID 2 by Motorola will be available at www.verizonwireless.com on August 11, and it will be in Verizon Wireless Communications Stores beginning August 12 for $199.99 after a $100 mail-in rebate with a new two-year customer agreement.  To learn more about DROID 2 in action, visit www.droiddoes.com .   To get started optimizing your web content for mobile devices, see http://www.adobe.com/devnet/devices/fpmobile


Check out this video http://www.adobe.com/go/fp101droid2 , where Diana Helander of Adobe demos the full web on the new DROID 2 by Motorola running Flash Player 10.1. DROID 2 is the first smartphone to ship out of the box with Flash Player 10.1 and benefit from HW decoding of all H.264 video profiles in Flash Player.

Setting Up Windows Service Dependencies – Oracle XE Example

Did you ever need a Windows service to startup, but only after other services are running? The LiveCycle Turnkey installation creates a dependency so that MySQL starts before JBoss. What if your application requires another DB such as Oracle XE to be running first?

Unfortunately, Oracle XE does not install this dependency, so that if you setup the Oracle XE DB to automatically start (the default installation), everything will be running, but you can’t access the XE DB. This can happen when the DB starts up before the TNS Listener, so that the TNS Listener doesn’t realize there’s a database running.

This Knowledge Base Article from Microsoft http://support.microsoft.com/kb/193888 describes how to do setup these dependencies, but the text does not match up with what I see in Windows 2003 EE R2, so I have attached some screen shots.

  1. Start->Run->regedit
  2. Navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\OracleServiceXE (swap OracleServiceXE for your service)
  3. Create a new Multi-String Value, by right-clicking on the background in the folder’s contents
    create_multi-string_value.png
  4. Change the name of the value to “DependOnService”
  5. Edit the value (right-click and select modify) and add the services that should be started before this one. You need to enter the service name exactly as it appears in the Windows Services application. For Oracle XE, it is the “OracleXETNSListener” service.
    edit_value.png
  6. Click OK
    change_multi-string_value_name.png
    View larger image.
  7. Verify that it was updated properly by checking the service properties
    service_properties.png

    service_dependencies.png