Search This Blog

Thursday, 12 March 2015

Adobe LiveCycle Designer Tip #8 - Bringing colour to your workspace (and other settings)

I recently received an upgraded computer, which meant I had to re-install LiveCycle Designer ... and find all my settings again.

Tools ... Options ... Document Handling


Increase the number of files in the Recently Used File List to 10.  This seems to be the maximum, although there is no error when a higher number is entered the value will not be saved.

Set the Create Backup Copy on Save, this will create a _BAK.pdf file (or a _BAK.xdp file) which gives you a chance to recover your work if Designer crashes on you.  The disadvantage of setting this option is when you edit a fragment the _BAK file will be created and the fragment will be duplicated when viewed in the fragment library.  Another way you can recover your work if Designer crashes to look for a PDF file in your Windows %temp% directory with some random looking name _1f7o26cap4d25e8q1t.pdf this is the file that is created whenever you perform a PDF Preview.

Tools ... Options ... Workspace


Under JavaScript Syntax Formatting ... select a custom color for strings and numbers, I use an orange color.  I used to have a boss who set his to red, he never wanted to see any red.  I'm not that strict so set mine to an orange.  The idea is to make you think if these values would be better off in a form variable or a dataset.

Select the Show Line Numbers checkbox, any runtime errors will refer to a line number so showing line numbers makes it easier to find the right line.  Just make sure there are no blank lines at the start of your script as these aren't counted when line numbers are displayed in error messages.

Tools ... Options ... Data Binding


Set the Show Dynamic Properties checkbox, this will enable the option to bind values in a drop down to the data connection

Set the Default Binding for New Subforms to "No Data Binding"

Window ... Drawing Aids


Deselect the Snap to Grid option to allow finer control over the form objects, typically I use flowed subforms but even with a positional subform it is usually easier to align with another object, under the Layout menu or learn the keyboard shortcuts, Ctrl-LeftArrow to align a group of fields on there left boundary, etc.

Tools ... Keyboard Shoutcuts


Add Ctrl-Shift-w for Warp in Subform and Ctrl-Shift-u for Unwarp Subform.  The default keyboard shortcuts are listed in Using Designer ES4 / Working with the Keyboard / Default keyboard shortcuts



Thursday, 5 March 2015

SOM Expressions with Relative Indexes

Most SOM expressions I work with have an absolute index number, something like form1[0].[0].Table1[0].Row1[0].TextField1[0] where all the numbers within the square brackets are absolute numbers.  But these numbers can be relative, that is have a positive or negative sign.  So if I was on TextField1 of row 2 and wanted to reference TextField1 of row 1 I could use a SOM expression like;

Row1.resolveNode('Row1[-1].TextField1');

Similarly if I have a series of fields with the same name and so have different indexes, say TextField[0], TextFIeld[1] etc, I can reference the next field, in document order, called TextField with a SOM expression

this.resolveNode('TextField[+1]').rawValue

We can also refer to the next field without knowing it's name using the class name reference (that is with a "#" character).

this.resolveNode('#field[+1]').somExpression

or the next button

this.resolveNodes('#field.(ui.oneOfChild.className == "button")').item(1).somExpression

This sample gives examples of these expressions and uses a relative SOM expression to calculate a running total in a table.

RelativeIndex.pdf

Saturday, 14 February 2015

Custom Properties

The XFA specification defines customs properties that can be store in a field, exclGroups (or radio buttons) or subforms under the <desc> and <extras> elements.  These allow us to write scripts that process a form but allow the individual fields and subforms to control that processing.  The example used here is a script that sets all the fields to their default value, except if an allowResetData property is set to false.  Other scenarios might be setting all fields to read only, except some, or some have additional processing, validation frameworks, setting min/max values, etc.

There doesn’t seem to be much difference between using the <desc> or <extras> elements but I tend to use <desc> as the names and values are shown in the Info palette.


The <desc> element is also were the <xs:annotation> information is stored is you are using a XML Schema for your data connection.
 
The XFA for a field with this custom property would then look like;
 
<field name="TextField1" w="62mm" h="9mm">
    <desc>
        <boolean name="allowResetData">1</boolean>
    </desc>
    <ui>
        <textEdit/>
    </ui>
    ...
</field>
 
There is no support for updating these values in LiveCycle Designer but I will include two macros that can be used to update the allowResetData property and hopefully can be used as a guide for updating your own properties  … or you could just edit the XML Source window. 

The data stored under a <desc> element can be typed, so JavaScript references are returned in properties with the appropriate data type.  The exception is the date/time related elements that are returned as strings. 



desc element
JavaScript
Data Type
Value Range
boolean Boolean 0 – false, 1 – true
date String  
dateTime

String  
decimal Number For integers;
9007199254740992 to -9007199254740992;
(Same as JavaScript, that is 253)
For floats
1.79E+308 to 1E-15 (max 15 decimal digits if specified by the fracDigits attribute e.g.
<decimal name="Decimal" fracDigits="15"/>,
Otherwise defaults to 2 decimal places
exData String  
float Number 9007199254740992 to -9007199254740992;
(Same as JavaScript)
For floats
1.79E+308 to 1E-08 (max 8 decimal digits)
image String Prints the number 2 in a width of 5 characters with "0" characters padding
integer Number 2147483647 to -2147483647
Attempting to assign a number outside this range raises an "Operation failed." GeneralError exception
text String  
time String  


I haven’t seen any limits documented, these are the values I have found by playing around. Also remember for decimal and float values that exceed the maximum integer value then the precision starts to fail like all usual float values, e.g.


9007199254740992 + 1 = 9007199254740992
9007199254740994 + 2 = 9007199254740994
9007199254740992 + 3 = 9007199254740996


More about float and decimal values here, http://en.wikipedia.org/wiki/Double-precision_floating-point_format

A value under a <desc> element value can be referenced directly in JavaScript using TextField1.desc.allowResetData.value but if the property does not exist on the form object you will get a “Invalid property get operation; desc doesn't have property 'allowResetData'” exception.  To check if a property exists use the namedItem() method, TextField1.desc.nodes.namedItem("allowResetData"), this will return null if the property does not exist or an object with a value property if it does.

So now the JavaScript function to process the form (or part of the form) could look like this;

function resetData(node)
{
    function pushResetDataList(node)
    {
        var allowResetData = node.desc.nodes.namedItem("allowResetData");
        // default is too allow reset
        if (allowResetData === null || allowResetData.value)
        {
            resetDataList.push(node.somExpression);
        }
    }

    function resetDataInner(node)    
    {
        if (node.className === "exclGroup" && !node.isNull) // don't reset fields that are null
        {
            pushResetDataList(node);
        }
        else
        {
            if (node.className === "field")
            {
                if (node.ui.oneOfChild.className !== "button" && !node.isNull) // buttons always null
                {
                    pushResetDataList(node);
                }
            }
            else
            {
                for
(var i = 0; i < node.nodes.length; i++)
                {
                    var nextNode = node.nodes.item(i);
                    if (nextNode.className === "instanceManager")
                    {
                        if (nextNode.count.toString() !== nextNode.occur.min)
                        {
                            nextNode.setInstances(nextNode.occur.min);
                        }
                    }
                    else
                    {
                        if (nextNode.className === "variables")
                        {
                            var scriptObject = nextNode.resolveNode("Script");
                            if (scriptObject && scriptObject.hasOwnProperty("resetData"))
                            {
                                scriptObject.resetData();
                            }
                        }
                        else
                        {
                            if (nextNode.isContainer && nextNode.className !== "draw")
                            {
                                resetDataInner(nextNode);
                            }
                        }
                    }
                }
            }
        }
    }
    var resetDataList = [];
    resetDataInner(node);
    if (resetDataList.length > 0)
    {
        xfa.host.resetData(resetDataList.join(","));
    }
}   

All subforms can have a script object and this resetData function looks for a script object called “Script” that contains a JavaScript function called “resetData” and if found executes it , the code under the nextNode.className === “variables”.

    var scriptObject = nextNode.resolveNode("Script");
    if (scriptObject && scriptObject.hasOwnProperty("resetData"))
    {
        scriptObject.resetData();
    }

This allows parts of the form to perform any custom operations required when a form is reset.  This example (CustomProperties.pdf) uses this function to remove a file that has been attached to the form.

I use two macros for setting and clearing allowResetData flag.  Once installed you will be able to select the appropriate form objects and run a macro instead of editing the XML Source.  To run select Tools … Macros … “Set allowResetData Flag to False” or Tools … Macros … “Clear allowResetData Flag”.  The macros and macro.xml configuration file are in the zip file (CustomProperties.Macros.zip).

If you haven’t written or installed a macro before then refer to the help page. Designer 10 - Macros

The <exData> element can be used to store rich text and be used to populate a Text control like;
Text1.value.exData.loadXML(TextField1.desc.ExData.saveXML(), true, true);

Likewise the <image> custom property can be used to store image and used to populate an image control like;  Image1.value.image.value = TextField1.desc.Image.value;

Form variables created using Form Properties … Variables are stored under a <variables> element, when created by LiveCycle Designer they are always text, but it is valid for them to be any of the types that can be used under the <desc> element.  This allows references to the variables in JavaScript to be typed, so by editing the XML Source can make your JavaScript code simpler, at least when dealing with Number and Boolean form variables.  Once you have made this change Designer will show them as a “?” icon in the hierarchy palette (see image below) but this has never caused any problem in my forms.

And looks like this in the XML Source window.


<variables>
    <text name="Text"/>
    <integer name="Integer"/>
</variables>



 

Wednesday, 28 January 2015

Adobe LiveCycle Designer Tip #7 - Formatting Tooltips

With the tooltips available with LiveCycle Designer there is no options to add formatting to a tooltip.  You can try using a subform and dynamically position it next to the field, like this sample Season Planner (or Year Planner) PDF Template.

One thing you can do is add some carriage returns to add some vertical space.  For a long time I was doing this by editing the XML Source and adding a carriage return character "&#xD;" in the toolTip value.

But you can do the same thing from the Accessibility palette by using a ctrl-Enter key combination. 

Seems everywhere you can enter a rich text value you can use shift-Enter but maybe because the Tool Tip value in the Accessibility palette is not rich text we have to use ctrl-Enter.

You can also gain some control over the tooltip width by using a non-breaking space (Ctrl-Shift-Space, which inserts a 0xc2a0 character) instead of a normal space.

Saturday, 10 January 2015

Custom Bulleted and Numbered Lists

With LiveCycle Designer ES3 came support for bulleted and numbered lists under the Paragraph palette.  This did make creating lists a lot easier but also added some restrictions;
          What ES3 gives you is


          What you might have been after
  • There is no option to add a leader (dots between the bullet/number and the text)
           Now you number list can look like
  • When read by a screen reader like NVDA the bullet characters or numbers are not announced.  In the example in the first dot point above, NVDA announces "What is your favourite fruit Apples Oranges Bananas" when what you probably wanted was "What is your favourite fruit bullet Apples bullet Oranges bullet Bananas"
In LiveCycle Designer the Text fields containing rich text that we need to use to implement a bullet list are implemented using a subset of xHTML.  ES3 introduced support for the ol, ul and li tags but prior to ES3 it was also possible to create bullet point lists and numbered list you just had to hand edit the xHTML, and use a negative text-indent and some tab-stops.

This sample PDF Form makes to easy, just enter the text of your dot points, select the type of bullets or numbers, the spacing and if you want leaders or not and the Draw element (which implements the Text object)  is output to the console.

You should see something like;

<draw name="Text1" w="196.85mm" minH="0in" xmlns="http://www.xfa.org/schema/xfa-template/3.6/">
   <value>
      <exData contentType="text/html">
         <body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"><p style="text-indent:-10mm;xfa-tab-stops:left leader (dots page 3pt) 10mm"><span style="font-size:9pt">1.</span><span style="xfa-tab-count:1"/><span style="font-size:9pt">Oranges</span></p><p style="text-indent:-10mm;xfa-tab-stops:left leader (dots page 3pt) 10mm"><span style="font-size:9pt">2.</span><span style="xfa-tab-count:1"/><span style="font-size:9pt">Apples</span></p><p style="text-indent:-10mm;xfa-tab-stops:left leader (dots page 3pt) 10mm"><span style="font-size:9pt">3.</span><span style="xfa-tab-count:1"/><span style="font-size:9pt">Bananas</span></p></body>
      </exData>
   </value>
   <ui>
      <textEdit allowRichText="1"/>
   </ui>
   <font typeface="Myriad Pro"/>
</draw>


To add this to your form it might be easiest to add a Text object in the place you need, select it, then switch to the XML Source view.  You should see a <draw>...</draw> element, which you can replace with the one copy and pasted from the JavaScript console.

The sample to generate the Draw element is Bullets.pdf.

A form containing samples of ES3 and customs bullet/number lists and how NVDA reads them is NVDA.Bullets.pdf.

Friday, 26 September 2014

Listing all fields in a form - The macro - Part Two

I have added some new columns to the Designer ES macro that creates a list of all the XFA objects within a form.

The new columns are;
  • somExpression
  • presence
  • field type (rich text or plain text)
  • the maximum length of the text field
The new macro can be downloaded here, XFAObjectLister.zip.

More details here, Listing all fields in a form - The macro.

Monday, 15 September 2014

Adobe LiveCycle Designer Tip #6 - Subform Indicators

One of the new features of Designer ES2 was Subform Indicators.  These are the green subform icons that appeared on the Design view.  Also as part of ES2 there was new option under the View menu to turn them off, which I did straight away as I didn’t see the use of them.

So if you are like me and did not realised that you can click on them to select the subform, you might what to give them another go.  They are particularly useful when you have many subforms sharing a top edge.


Now all we need is an indicator to allow us to select an exclGroup