Search This Blog

Friday 28 February 2014

Updated: Drop-Down List Control with auto-complete (Searchable Drop-Down List)

I have made some changes to my "Drop-Down List Control with auto-complete" sample. 

To start I would like to explain the title of this sample, as it is really a textbox pretending to be the UI portion of the drop down list and a textbox pretending to be the list portion of drop down list.  I am not sure what I would have called the sample but "Drop-Down List Control with auto-complete" and "Searchable Drop-Down List" came from the title of the first two forum posts I tried to answer with this sample.  It seems we can't update the entries in a drop down list when the list is open, which is why I have tried to mimic the behaviour with these two controls.

The changes I have made are;
  • Display the list when the user enters the field, so the user knows this field is special
  • Show some "ghost text", giving instructions to the user
  • Sort the values in the list
  • Allow for strict scoping
  • Allow for keyboard users, previous the sample only worked with the mouse.

To use this in your own form

  • Copy the subform DropDownList to you own form
  • If you don't want the option to match first characters/match any characters the delete the RadioButtonList under the DropDownList subform.  You may need to update the code in the initialise event of DropDownList subform to set the default option, currently it defaults to match first characters.
  • Change the null display pattern in the Search textbox, to suit the items you are search over.  This is how the "ghost text" is implemented and currently says "'Search by country name".
  • Update the code in the change event of the Search textbox, this is where the matching is performed against the list of countries.  The format of the countries XML list is;
    • <Country>
            <Region>Oceania</Region>
            <Code>36</Code>
            <Name>Australia</Name>
        </Country>
    • So the binding expression for match first characters is;
      '$record.Country.[Lower(Left(Name,' + (xfa.event.newText.length) + ')) == "' + xfa.event.newText.toLowerCase() + '"]'
    • This matches the left characters of the Name element against the characters entered in the Search textbox, xfa.event.newText.  A case insensitive match is made by calling toLowerCase() on the xfa.event.newText and calling the FormCalc function Lower on the Name element.  I find the using FormCalc in binding expressions to be about four times faster.

The sample

For a PDF version of the sample with the countries data already imported download CountriesV2.pdf.  For the XDP template download CountriesV2.xdp and the preview data Countries.xml.

Sunday 9 February 2014

Listing all fields in a form - The macro

Radzmar has written a macro that makes Listing all fields in a form method I described in a previous blog a lot easier.

The macro contains the XSLT so you no longer need to copy it around and the macro also resolves the namespace so the XSLT will work for all Adobe Reader target versions.

Run the macro and you will be prompted to save the XML file that can be opened into Microsoft Excel as an XML table, without having to make temporary changes to your XDP file.

Download the macro in XFAObjectList.zip which contains the JavaScript of the macro and the macro.xml file Designer uses to create the Tools ... Macros menu items.

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.