Search This Blog

Showing posts with label Rich Text. Show all posts
Showing posts with label Rich Text. Show all posts

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.

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.

Saturday, 12 April 2014

Programmatically updating Rich Text (or xHTML)

In a previous sample I gave an example of updating the rich text of a draw object using E4X.  In this sample I want to show an alternative using the Span objects from the Adobe Reader API. 

The Span object does not cater for all the attributes of rich text that are supported in an XFA form but sometimes can be easier than using E4X.

So an example, the rich text "Please click the red button" is generated by the xHTML;

<body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
    <p style="letter-spacing:0in">
        Please click the<span style="color:#ff0000">red</span>button
    </p>
</body>

As an array of Spans objects this is represented as

({text:"Please click the "})
({text:"red", textColor:["RGB", 1, 0, 0]})
({text:" button"})


Then the code to change all the red text to green would be;

var spans = util.xmlToSpans(Text1.value.exData["##xHTML"].saveXML());
for (var i = 0; i < spans.length; i++)
{

    if (spans[i].textColor && color.equal(spans[i].textColor, color.red))
    {

        spans[i].textColor = color.green;
        spans[i].text = "green";
    }
}

var xHTML = util.spansToXML(spans);
Text1.value.exData.loadXML(xHTML, falsetrue);

The color object used in this code is also from the Adobe Reader API, it defines some common colors  (that is black, white, dkGray, gray, ltGray, red, green, blue, cyan, magenta and yellow).  As well as the color.equal() method it also has a color.convert() method so to change all the colors to a gray scale we could;

var spans = util.xmlToSpans(Text1.value.exData["##xHTML"].saveXML());
for (var i = 0; i < spans.length; i++)
{

    if (spans[i].textColor)
    {
        spans[i].textColor = color.convert(spans[i].textColor, "G");
    }

}
var xHTML = util.spansToXML(spans);
Text1.value.exData.loadXML(xHTML, falsetrue);

If anyone still needs to have a color form for the screen and a black and white version for printing and uses rich text then this code could go in the prePrint event and then in the postPrint event you could revert to the original formatting with;

Text1.nodes.remove(Text1.value);
Removing the changes made in the Form DOM resets the properties to their initial values as defined in the Template DOM.

To build a rich text value from scratch we could;

var spans = [];

spans.push({text:"Hello "});

spans.push({text:NameField.rawValue, fontWeight:700, fontStyle:"italic"});
spans.push({text:", I hope you like this sample"});

var xHTML = util.spansToXML(spans);

Text1.value.exData.loadXML(xHTML, false, true);

If you need to change a plain-text Text field into a rich-text one then you can use the following code;

if (Text1.value.oneOfChild.className === "text")
{
    Text1.value.nodes.remove(Text1.value.text);
    var exDataNode = xfa.form.createNode("exData");
    Text1.value.nodes.append(exDataNode);
}

The sample SpanDemos.pdf includes a couple of other simple examples, as well as a more complicated example that will take the body element of the rich text then format and colorize it.  This sample also shows a workaround for the lack of support for the xfa-spacerun:yes style attribute in the Span objects.


background-color style attribute

This attribute is not mentioned in the XFA spec and there is no support for it with the Designer UI but Reader will render the background color, you just need to enter it in the XML Source view.  The trick with using background-color is that all elements following the one the style is applied to will inherit the color.  In an HTML page only the descendent elements would inherit the color.  This just means you need a second background-color style attribute to reset the color.  Designer doesn't play well with this attribute as every time you edit the text using the Design view you will have to add the second background-color style attribute back.

The color can be specified in hexadecimal or decimal;

background-color:#C4C4C4     or     background-color:rgb(196,196,196)

You can see an example of the background-color style attribute in this sample. 

I haven't gone though all the style attributes to see which ones are supported, but I did try adding a border and that didn't work for me.

Saturday, 1 February 2014

Adding values in a form to an email

Consider we have some text like "Please contact us or visit our website for more information" in our form.  So if our user clicks on "contact us" we open an email client and if they click on "website" we open the web page in the browser.

Before Designer ES2 we would have done this with two buttons with no background or border and using positioned layout carefully placed them in the correct spot.  The "contact us" button would have called the app.mailMsg and the "website" button would have called app.launchURL.

Since Designer ES2 we can add these as hyperlinks directly into a text control.  This means the links are correctly announced when using the accessibility screen readers,  but it also makes it harder to include values from the form in the email.  We might want to send the email to different recipients, use different subject lines or generate different body text depending on other values selected in the form.

If you look at the XML Source for the text control you will see a rich text value that looks something like;

<body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
  <p style="text-decoration:none;letter-spacing:0in">
   Please
   <a href="
mailto:sample@example.com">contact us</a>
   or visit our
   <a href="
http://adobelivecycledesignercookbookbybr001.blogspot.com.au/">website</a>
   for more information
  </p>
</body>


The full syntax for the mailto link is

mailto:emailaddress?cc=emailaddress?bcc=emailaddress?subjext=text?body=text

Even though the Designer interface only supports the to email address and the subject header, the cc, bcc and body still work. We just need some code to update the mailto link.

To do this I am using E4X.

To start load the rich text value into an E4X XML object,  to do this we must first remove the XML declaration.  Note that the class name of the rich text value is "#html" and to refer to an element we need to prefix it with a "#" character, which is why we see the rather strange looking double "##".

var body = new XML(Text1.value.exData["##xHTML"].saveXML().replace(/^<\?xml\s+version\s*=\s*(["'])[^\1]+\1[^?]*\?>\n*/, "")); 

Declare the namespace and set the white space handling to be the same as Adobe Designer.

var xhtml = new Namespace("
http://www.w3.org/1999/xhtml");
XML.ignoreWhitespace = false;
XML.prettyPrinting = false;


Loop though all the anchor tags

for each (var anchorTag in body..xhtml::a)
{


  Look for the "mailto:" tag

 if (
anchorTag.@href.toString().indexOf("mailto:") === 0)
 {


   Generate the new "mailto" tag based on fields within the form

  attributes = [];
  
anchorTag.@href = "mailto:" + ToAddress.rawValue;
  if (!CCAddress.isNull)
  {
   attributes.push("cc="+CCAddress.rawValue);
  }
  if (!BCCAddress.isNull)
  {
   attributes.push("bcc="+BCCAddress.rawValue);
  }
  if (!Subject.isNull)
  {
   attributes.push("subject="+encodeURI(Subject.rawValue));
  }
  if (!Body.isNull)
  {
   attributes.push("body="+encodeURI(Body.rawValue));
  }
  if (attributes.length > 0)
  {
   
anchorTag.@href += "?" + attributes.join("&");
  }
  anchorTag.setChildren(anchorTag.toString());
 }
}


Load the new value back into the text control.

Text1.value.exData.loadXML(body.toXMLString(), /* Ignore root node */ false, /* Overwrite content */ true);


If you wanted to send an email to a list of addresses just separate them with a comma.

Enabling / Disabling a hyperlink

We can use a very similar approach to enable and disable a hyperlink.

To disable, we would do;

anchorTag.@style = "color:#969696";
delete anchorTag.@href;


To enable, we would do;

delete anchorTag.@style;
anchorTag.@href = "http://adobelivecycledesignercookbookbybr001.blogspot.com.au/";



To see this in action download this sample, EmailHyperlink.pdf.