Search This Blog

Thursday, 26 March 2015

Handling a full stop in a XML element name


The “.” (full stop) character is valid in an XML name, this means there can be cases were you need to escape a full stop in a SOM expression.

This is the default format when using SQL Server and the FOR XML AUTO option and the table has
a schema, you will end up with XML like;

<ClientMgmt>
<ClientMgmt.ClientDetails name="..." />
<ClientMgmt.ClientDetails name="..." />


In a SOM Expression the full stop needs to be escaped with a “\” (backslash), when we put this in JavaScript code we again need to escape the backslash, so end up with three backslash characters.
$data.resolveNodes('ClientMgmt.ClientMgmt\\\.ClientDetails[*]')
Interestingly when trying the same in the Acrobat JavaScript debugger you need to use four backslash characters.

Thursday, 19 March 2015

Going deeper with floating fields

Floating fields allow variable text to be inserted within a text object.  A floating field is referenced within a rich text field using XFA extension to the xHTML <span> element, e.g.

As inserted by the LiveCycle Designer Insert ... Floating Field command you will get something like this in the XML Source

<span xfa:embedType="uri" xfa:embedMode="raw" xfa:embed="#floatingField007456"/>

The full XFA syntax for a floating field is;

<span xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"
      xfa:embedType="uri | som"
      xfa:embed="<SOM expr> | <uri>"
      xfa:embedMode="raw | formatted"/>

embedType

When the embedType has a value of "uri" then the embed value will be the id of the floating field, prefixed with a "#" symbol.

But you can see from the syntax that there are some other options available.  Sometimes we might create a floating field bind it to our data connection just to display the value embedded in some text.  Say the floating field was bound to $data.formData.firstName then we could change our span element to reference the data connection directly, in which case we don't need the floating field at all.

Another situation you may need to use a SOM expression in an embedded field is when you have multiple levels of repeating data, such as a list of countries within which we have a list of cities


If I wanted to use a floating field to display the country element within the repeating city element, there is no way Designer can make the reference.  Designer will give you a binding expression like $record.counties.country, which will always return you the first country.  In this case we can again change the embedType to "som" but use a form object SOM expression, something like;

<span xfa:embedType="som" xfa:embedMode="raw" xfa:embed="countries.country"/>

This will resolve to the form object with the SOM expression countries.country, which should be the right country for the city we are processing.

embedMode

By default the embedMode is set to "raw", which means only the floating fields value is inserted, all font formatting is taken from the surrounding text.  A value of formatted for embedMode means the font attributes of the inserted text are taken from the inserted field, which can be useful if we need to dynamically update them as in this sample, FloatingFields.pdf.

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.