10.4 A More Complete Example


So far we've looked at only the bare minimum of what goes into making an InfoPath solution. Now we'll jump in from the opposite extreme and show a complete, working example. In addition to illustrating more features of the form definition file, this example will further demonstrate how InfoPath interprets certain XSLT constructs to establish implicit bindings between HTML nodes in the form view and XML nodes in the source document. So far, we've seen how text bindings are established, using the xsl:value-of instruction. This example will additionally demonstrate the use of structural bindings, as we'll see in Section 10.4.3.

While the example in this section illustrates a great deal of functionality, there are still a number of features not covered here. I recommend consulting the InfoPath online Help system to fill in the gaps. In particular, consult the "InfoPath XSF Reference" for comprehensive coverage of the form definition file format, including a reference for the XSF schema. From the InfoPath Help task pane, select Table of Contents InfoPath Developer's Reference InfoPath XSF Reference.


Figure 10-5 shows our example form from the user's perspective. It is a form for creating new "events," which might ultimately be displayed in the context of an event calendar. The "Title" field is surrounded by a blue border. This is InfoPath's built-in behavior for indicating the currently active field, which is independent of how the view stylesheet instructs the field to be rendered. The field is also underlined in red, because the schema requires the field to be non-empty (see Section 10.4.1 later in this section). Until the user fills out the field, the document will remain invalid. Likewise, the date and time fields remain underlined until the user enters valid data.

Figure 10-5. A sample InfoPath form before being filled out
figs/oxml_1005.gif


The "Form Tips" task pane is a custom HTML-based task pane specific to our solution. Apart from giving the user some form entry tips, it actually serves some auxiliary roles in our solution, as we'll see in Section 10.4.5.

Figure 10-6 shows the same form after being mostly filled out. The user has added the optional "Location" section and is currently selecting a date using InfoPath's built-in date picker control.

Figure 10-6. Our sample form while being filled out
figs/oxml_1006.gif


Figure 10-7 shows that the "Description" field may contain more than one paragraph. This is called a "repeating section." The contextual editing menu, which appears either when the user clicks the blue down-arrow on the left or right-clicks anywhere inside the section, displays buttons for inserting and removing paragraphs. Also, the text within the paragraph can be formatted. The text formatting buttons, such as bold and italic, are enabled in InfoPath's formatting toolbar. This type of field is called a "rich text" field.

Figure 10-7. Structural context menu buttons for repeating elements
figs/oxml_1007.gif


Figure 10-8 shows the contextual editing menu for the section labeled "Single-day event with time." The option to replace the element with another kind of scheduling for the event corresponds to a choice group in the XML schema.

Figure 10-8. Structural editing context menu button for replacing an element in a choice group
figs/oxml_1008.gif


Figure 10-9 shows the section and corresponding structural editing context menu after replacing the element.

Figure 10-9. Structural editing context menu button after replacing element
figs/oxml_1009.gif


Finally, whether the form is saved to the user's hard drive or submitted to a backend system, the resulting XML is shown in Example 10-9.

Example 10-9. The instance XML created by filling out the event form
<?mso-application prog?> <?mso-infoPathSolution PIVersion="1.0.0.0"   href="http://myserver/events/solution.xsn" language="en-us"   productVersion="11.0.5329" ?> <event>   <title>Pizza Party</title>   <description>     <p xmlns="http://www.w3.org/1999/xhtml">Here we describe our party in <em>italics</em> or <strong>bold</strong>.</p>     <p xmlns="http://www.w3.org/1999/xhtml">This is a second paragraph in which to describe our party.</p>   </description>   <location>Top of the Space Needle</location>   <when>     <single-day date="2003-09-13" start-time="20:00:00" end-time="23:00:00"/>   </when> </event>

This XML document conforms to the schema included in our solution. Note that the rich text vocabulary used is indeed XHTML, with em and strong elements for italic and bold, respectively.

10.4.1 The XSD Schema

Example 10-10 shows the top-level schema document for our solution's XSD schema.

Example 10-10. The XSD schema for events, schema.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"   elementFormDefault="qualified" xmlns:xhtml="http://www.w3.org/1999/xhtml">     <xs:import namespace="http://www.w3.org/1999/xhtml"              schemaLocation="paragraphs.xsd"/>     <xs:element name="event">     <xs:complexType>       <xs:sequence>         <xs:element ref="title"/>         <xs:element ref="description"/>         <xs:element ref="location" minOccurs="0"/>         <xs:element ref="when"/>       </xs:sequence>     </xs:complexType>   </xs:element>       <xs:element name="title">     <xs:simpleType>       <xs:restriction base="xs:string">          <xs:minLength value="1"/>       </xs:restriction>     </xs:simpleType>   </xs:element>       <xs:element name="description">     <xs:complexType>       <xs:sequence>         <xs:element maxOccurs="unbounded" ref="xhtml:p"/>       </xs:sequence>     </xs:complexType>   </xs:element>       <xs:element name="location" type="xs:string"/>       <xs:element name="when">     <xs:complexType>       <xs:choice>         <xs:element ref="single-day"/>         <xs:element ref="multi-day"/>       </xs:choice>     </xs:complexType>   </xs:element>       <xs:element name="single-day">     <xs:complexType>       <xs:attribute name="date" use="required" type="xs:date"/>       <xs:attribute name="start-time" use="required" type="xs:time"/>       <xs:attribute name="end-time" type="xs:time"/>     </xs:complexType>   </xs:element>       <xs:element name="multi-day">      <xs:complexType>       <xs:attribute name="start-date" use="required" type="xs:date"/>       <xs:attribute name="end-date" use="required" type="xs:date"/>     </xs:complexType>   </xs:element>     </xs:schema>

Primary things to note about this schema include:

  • The title element must not be empty.

  • The description element must contain one or more xhtml:p elements.

  • The location element is optional.

  • The content of when consists of a choice between a single-day element or a multi-day element.

  • The date- and time-related fields must have xsd:date and xsd:time values, respectively.

Example 10-11 shows the imported schema document that declares the xhtml:p element. The (highlighted) content model of this element is precisely what InfoPath considers rich text content, i.e., mixed content with any number of elements in the XHTML namespace. If you want to use rich text editing in InfoPath, your schema must have a type definition that looks like this.

Example 10-11. The schema for XHTML paragraphs, paragraphs.xsd
<xs:schema targetNamespace="http://www.w3.org/1999/xhtml"   elementFormDefault="qualified"   xmlns:xs="http://www.w3.org/2001/XMLSchema">       <xs:element name="p">     <xs:complexType mixed="true">       <xs:sequence>         <xs:any namespace="http://www.w3.org/1999/xhtml"                 processContents="lax" minOccurs="0" maxOccurs="unbounded"/>       </xs:sequence>     </xs:complexType>   </xs:element>     </xs:schema>

The constraints imposed by our schema are all enforced by InfoPath in editing mode. In particular, InfoPath notifies the user if the underlying document becomes invalid, whether by drawing a red underline or box around the invalid field, or showing a dialog box indicating that the user may not, for example, remove the one remaining xhtml:p element. As far as InfoPath in editing mode is concerned, validation is where the role of schemas ends. The schema is not directly used by the InfoPath XML editor to generate UI, but only to validate intermediate editing results. Another way of saying this is that the schema solely has restrictive, rather than generative, semantics.

However, InfoPath in design mode is another matter. In fact, should we decide to create a solution in design mode starting with this schema (which is exactly what we'll look at doing in "Creating a Simple Solution from an XSD Schema"), it turns out that we need to make one internal change to our schema in order for the full range of functionality in design mode to be available to us.

10.4.1.1 Making a concession for design mode

The schema as listed above works perfectly well for our hand-made solution in InfoPath editing mode. When starting with this schema in design mode, however, InfoPath fails to recognize the xhtml:p element as a "field" having data type "XHTML," ironically because of the fact that the complex type declaration (whether named or anonymous, as above) occurs inside a schema document whose target namespace is the XHTML namespace. To get around that, we can simply offload the type declaration to another imported schema document, using an arbitrary target namespace. Example 10-12 shows the updated paragraphs.xsd schema document. We'll use this revision from now on instead, in order to facilitate our design mode example later on.

Example 10-12. The revised schema document for XHTML paragraphs, paragraphs.xsd
<xs:schema targetNamespace="http://www.w3.org/1999/xhtml"   elementFormDefault="qualified"   xmlns:rich="http://oreilly.com/dummy-namespace-for-rich-text-decl"   xmlns:xs="http://www.w3.org/2001/XMLSchema">       <xs:import namespace="http://oreilly.com/dummy-namespace-for-rich-text-decl"              schemaLocation="xhtmlType.xsd"/>       <xs:element name="p" type="rich:xhtml"/>     </xs:schema>

Example 10-13 shows xhtmlType.xsd, which paragraphs.xsd imports.

Example 10-13. The XHTML type declaration schema document, xhtmlType.xsd
<xs:schema elementFormDefault="qualified"   targetNamespace="http://oreilly.com/dummy-namespace-for-rich-text-decl"   xmlns:xs="http://www.w3.org/2001/XMLSchema">       <xs:complexType name="xhtml" mixed="true">     <xs:sequence>       <xs:any namespace="http://www.w3.org/1999/xhtml"               processContents="lax" minOccurs="0" maxOccurs="unbounded"/>     </xs:sequence>   </xs:complexType>     </xs:schema>

This is not a concession you will normally have to make. (Of course, you'll never have to make it if you never use design mode.) It is unique to situations in which you want to use and edit specific elements in the XHTML namespace with greater control than what the black box of rich text editing gives you. We could have simply made the description element a rich text field, but in that case we would not have been able to enforce the rule that it contain only a sequence of xhtml:p elements.

10.4.2 The Initial XML Template

Example 10-14 shows the initial XML document template that InfoPath works from when a user tries to fill out a new form. The optional location element is absent by default, and the default choice for the content of the when element is single-day, without the optional end-time attribute. Also, the infoPathSolution PI refers to the relative path of the form definition file.

Example 10-14. The initial XML document, template.xml
<?mso-application prog?> <?mso-infoPathSolution href="manifest.xsf" PIVersion="1.0.0.0"?> <event>   <title></title>   <description>     <p xmlns="http://www.w3.org/1999/xhtml"></p>   </description>   <when>     <single-day date="" start-time=""/>   </when> </event>

10.4.3 The XSLT Stylesheet

Example 10-15 shows the complete XSLT stylesheet that defines our solution's default editing view. The stylesheet consists of pure XSLT sprinkled with some annotations in the xd namespace. The highlighted start and end tags in this example identify all of the HTML nodes in the result tree that have bindings to XML nodes in the source tree, whether implicitly or explicitly (using the xd:binding attribute).

Example 10-15. The default view stylesheet, default.xsl
<xsl:stylesheet version="1.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"   xmlns:xdFmt=        "http://schemas.microsoft.com/office/infopath/2003/xslt/formatting"   xmlns:xhtml="http://www.w3.org/1999/xhtml">       <xsl:template match="/event">     <html>       <head>         <style type="text/css">           body { font-family: Verdana; }                .optionalPlaceHolder { padding-left: 20px;                                  behavior: url(#default#xOptional);                                  font-size: xx-small;                                  font-weight: normal; }               .field { border: 1pt solid #dcdcdc; font-size: x-small; }         </style>       </head>       <body>         <h1>Create New Event</h1>         <table cellspacing="2" cellpadding="10">           <colgroup span="1" width="100" valign="top"                     style="font-weight: bold;"/>            <colgroup span="1" width="450" valign="top"/>            <tr>             <td>Title:</td>             <td>               <div >                 <xsl:value-of select="title"/>               </div>             </td>           </tr>           <tr>             <td>Description:</td>             <td>               <xsl:apply-templates select="description/xhtml:p"/>             </td>           </tr>           <xsl:choose>             <xsl:when test="location">               <xsl:for-each select="location">                 <tr>                   <td>Location:</td>                   <td>                     <div >                       <xsl:value-of select="."/>                     </div>                   </td>                 </tr>               </xsl:for-each>             </xsl:when>             <xsl:otherwise>               <tr>                 <td colspan="2"                      xd:xmlToEdit="locationElement" tabindex="0">                   <xsl:text>Click here to add optional Location</xsl:text>                 </td>               </tr>             </xsl:otherwise>           </xsl:choose>           <tr>             <td>When:</td>             <td>               <xsl:apply-templates select="when/*"/>             </td>           </tr>         </table>         <input type="button" value="Submit Event" xd:Ctrl/>       </body>     </html>   </xsl:template>       <xsl:template match="xhtml:p">     <p >       <xsl:copy-of select="node( )"/>     </p>   </xsl:template>       <xsl:template match="single-day">     <div>       <div style="font-weight: bold;">Single-day event with time:</div>       <table>         <colgroup span="1" width="100" style="padding: 5px;"/>         <tr>           <td>Date: </td>           <td>             <xsl:call-template name="make-date-picker">               <xsl:with-param name="date-node" select="@date"/>             </xsl:call-template>           </td>         </tr>         <tr>           <td>             <xsl:if test="@end-time">Start </xsl:if>             <xsl:text>Time: </xsl:text>           </td>           <td>             <xsl:call-template name="make-time-field">               <xsl:with-param name="time-node" select="@start-time"/>             </xsl:call-template>           </td>         </tr>           <xsl:choose>           <xsl:when test="@end-time">             <xsl:for-each select="@end-time">               <tr>                 <td>End time: </td>                 <td>                   <xsl:call-template name="make-time-field">                     <xsl:with-param name="time-node" select="."/>                   </xsl:call-template>                 </td>               </tr>             </xsl:for-each>           </xsl:when>           <xsl:otherwise>             <tr>               <td colspan="2"                     xd:xmlToEdit="end-time" tabindex="0">                 <xsl:text>Click here to add optional End Time</xsl:text>               </td>             </tr>           </xsl:otherwise>         </xsl:choose>       </table>       </div>   </xsl:template>        <xsl:template match="multi-day">     <div>       <div style="font-weight: bold;">Multi-day event:</div>       <table>         <colgroup span="1" width="100" style="padding: 5px;"/>         <tr>           <td>Start date: </td>           <td>             <xsl:call-template name="make-date-picker">               <xsl:with-param name="date-node" select="@start-date"/>             </xsl:call-template>           </td>         </tr>         <tr>           <td>End date: </td>           <td>             <xsl:call-template name="make-date-picker">               <xsl:with-param name="date-node" select="@end-date"/>             </xsl:call-template>           </td>         </tr>       </table>     </div>   </xsl:template>       <xsl:template name="make-date-picker">     <xsl:param name="date-node"/>     <span xd:disableEditing="yes">       <span              xd:binding="$date-node"             xd:xctname="DTPicker_DTText"             contentEditable="true"             style="BEHAVIOR: url(#default#CalPopup)                              url(#default#urn::controls/Binder)                              url(#default#Formatting);                    width: 100;"             xd:innerCtrl="_DTText"             xd:boundProp="xd:num"             xd:datafmt='"date","dateFormat:Short Date;"'>         <xsl:attribute name="xd:num">           <xsl:value-of select="$date-node"/>         </xsl:attribute>         <xsl:value-of select="xdFmt:formatString($date-node,                                                  'date',                                                  'dateFormat:Short Date;')"/>       </span>       <button style="height:18px; width:20px;                      BEHAVIOR: url(#default#DTPicker);"               tabindex="-1">         <img src="/books/2/633/1/html/2/res://infopath.exe/calendar.gif"/>       </button>     </span>   </xsl:template>       <xsl:template name="make-time-field">     <xsl:param name="time-node"/>     <span xd:disableEditing="yes">       <span              xd:binding="$time-node"             contentEditable="true"             xd:xctname="PlainText"             xd:datafmt='"time","noSeconds:1;"'             xd:boundProp="xd:num"             style="BEHAVIOR: url(#default#urn::controls/Binder)                              url(#default#Formatting);                    width: 100;">         <xsl:attribute name="xd:num">           <xsl:value-of select="$time-node"/>         </xsl:attribute>         <xsl:value-of select="xdFmt:formatString($time-node,                                                  'time',                                                  'noSeconds:1;')"/>       </span>     </span>   </xsl:template>     </xsl:stylesheet>

10.4.3.1 Text bindings

The title field shows an example of a text binding:

  <div >     <xsl:value-of select="title"/>   </div>

This is the same kind of binding that we saw in our first stylesheet, in Example 10-3. Our current example has one other implicit text binding, corresponding to the location field. As we've seen, text bindings cause the corresponding HTML element to be rendered as an editable field in the InfoPath editing view. To make these fields look more like actual text boxes, they are each associated with the CSS class, field, which is declared inside the HTML document head and which adds a thin border to the element:

  .field { border: 1pt solid #dcdcdc; font-size: x-small; }

This serves no function other than to make the element look more like a form field to the user.

10.4.3.2 Rich text bindings

A rich text binding is essentially no different than a text binding, except that it maps an HTML element in the result tree to an XHTML-valued XML element in the source tree, i.e., an element that can contain XHTML elements. This stylesheet contains one rich text binding shown in the template rule for xhtml:p elements:

  <xsl:template match="xhtml:p">     <p >       <xsl:copy-of select="node( )"/>     </p>   </xsl:template>

Like the rules for the implicit creation of regular text bindings, the following two conditions must be met for a rich text binding to be created when an xsl:copy-of instruction is present:

  • The xsl:copy-of instruction must be the only child element of a valid HTML element (p in this case).

  • The expression in the select attribute must evaluate to a node-set containing zero or more text nodes and elements in the XHTML namespace that share the same parent element in the source document (xhtml:p in this case).

This text binding causes the HTML p element in the editing view to be rendered as an editable field, just as with a regular text binding. However, for it to function as a rich text field, there is one further requirement:

  • The form definition file must explicitly declare this field, with rich text editing enabled.

Until this final condition is met, the field will behave like any other text binding, with the formatting toolbar disabled. See Section 10.4.4.6, later in this chapter, to learn how to declare a rich text binding using the xsf:xmlToEdit element.

10.4.3.3 Structural bindings

Unless explicitly disabled, structural bindings are implicitly created whenever an XSLT template rule, named template, or xsl:for-each instruction, if it has any literal result elements as immediate children, is invoked. The binding occurs between the "current node," in XSLT terms, and each HTML element in the result tree that is created by a literal result element that is the immediate child of the xsl:template or xsl:for-each element. For example, the template rule that matches xhtml:p elements creates a structural binding between the p element in the result tree and the xhtml:p element in the source tree:

  <xsl:template match="xhtml:p">     <p >       <xsl:copy-of select="node( )"/>     </p>   </xsl:template>

This structural binding occurs because xhtml:p is the current node, and the HTML p literal result element is the immediate child of xsl:template. Thus, it turns out that the resulting HTML p element, unlike any other element created by our stylesheet, has not one, but two bindings: a (rich) text binding and a structural binding. Both bindings map between the same two nodes.

Our stylesheet creates a number of structural bindings, one for each literal result element that is an immediate child of xsl:template or xsl:for-each. All of their corresponding start and end tags are highlighted in Example 10-15. Scanning down the stylesheet, we see structural bindings for html, tr, p, div, tr, and div, each of which maps to the current node at that point in stylesheet processing. On the other hand, the last two templates in the stylesheet, which happen to be named templates (make-date-picker and make-time-field) as opposed to template rules, do not create structural bindings. This is because their respective span element children explicitly prevent those bindings from being created by invoking xd:disableEditing="yes".

All of this begs the question, "What is the point of a structural binding?" The answer is that, whereas text bindings (whether rich or not) enable text editing, structural bindings enable structural editing. Examples of structural editing actions were included in Figures 10-7, 10-8, and 10-9, under friendly names like "Insert Paragraph Below", and "Replace with All-day or Multi-day Event." However, structural editing actions are not automatically available just because there is a structural binding. The structural binding is merely a prerequisite for structural editing. To enable structural editing, the form definition file must explicitly declare buttons, associate them with editing actions, and map them to XML nodes in the source document. These mappings, if they are to have any effect on the form, rely on the presence of corresponding structural bindings. To see how this is done, see "Editing components" later in this chapter.

10.4.3.4 Date picker control

The precise rules for how to create a date picker control are not documented by InfoPath. The best approach, at this point, is to learn and follow by example. The make-date-picker template, shown again below, explicitly establishes a binding with an XML source node through the use of the xd:binding attribute. It is evaluated in the current XSLT context; in this case, the bound node is whatever value is passed to the template through the date-node parameter. This allows us to reuse the template for each date picker control we need to create in our form.

  <xsl:template name="make-date-picker">     <xsl:param name="date-node"/>     <span xd:disableEditing="yes">       <span              xd:binding="$date-node"             xd:xctname="DTPicker_DTText"             contentEditable="true"             style="BEHAVIOR: url(#default#CalPopup)                              url(#default#urn::controls/Binder)                              url(#default#Formatting);                    width: 100;"             xd:innerCtrl="_DTText"             xd:boundProp="xd:num"             xd:datafmt='"date","dateFormat:Short Date;"'>         <xsl:attribute name="xd:num">           <xsl:value-of select="$date-node"/>         </xsl:attribute>         <xsl:value-of select="xdFmt:formatString($date-node,                                                  'date',                                                  'dateFormat:Short Date;')"/>       </span>       <button style="height:18px; width:20px;                      BEHAVIOR: url(#default#DTPicker);"               tabindex="-1">         <img src="/books/2/633/1/html/2/res://infopath.exe/calendar.gif"/>       </button>     </span>   </xsl:template>

The span element child of xsl:template (which prevents a structural binding via xd:disableEditing="yes") contains two child elements: span and button. These must occur as adjacent sibling elements for the correct behavior to result. The span element has a number of attributes in the xd namespace, most (if not all) of which must be present for the date picker control to work correctly. The xd:num attribute (which initializes the date picker control, determining what calendar date will be highlighted) is created using the xsl:attribute instruction only because that is how the InfoPath form designer outputs the attribute. It will also work just fine if you use a literal result attribute and an attribute value template instead (as in xd:num="{$date-node}").

The contentEditable attribute, which is an extension to HTML that's supported by Internet Explorer, is also required. The CSS BEHAVIOR property is part of IE's behavioral extensions to CSS. The URL-based values are specific to InfoPath. The xd:datafmt attribute defines a translation from what the user types in to the underlying value to be stored. Specifically, it allows the user to enter a wide range of date formats, such as 9/22/03 or September 22, 2003, while storing the value using the ISO 8601 format, i.e., 2003-09-23. Conversely, the xdFmt:formatString( ) extension function is used to translate from the XML source value in the standard format to the localized format indicated by the second two arguments passed to the function. When the user tabs out of the field, its value, regardless of how the user entered the data, will be displayed in the localized format, e.g., 9/22/03. Finally, the button element creates the calendar icon button that, when clicked, displays the calendar date picker shown back in Figure 10-6. When the user selects a date, that date value populates the node to which the preceding span element is bound.

10.4.3.5 Time field formatting

To create a time-valued field, as well as a number of other types of InfoPath form controls, you should again take the approach of learning and doing by example. This is where InfoPath's sample forms are indispensable. For many kinds of controls, the sample forms represent the only documentation that's currently available, if you want to create such controls by hand. The declaration of the time field in our example is similar to that of the date picker. A named template, make-time-field, can be reused for each time field we want to create in the form.

10.4.4 The Form Definition File

Example 10-16 shows the entire form definition file for our example solution.

Example 10-16. The form definition file, manifest.xsf
<xsf:xDocumentClass solutionFormatVersion="1.0.0.0"   xmlns:xsf=     "http://schemas.microsoft.com/office/infopath/2003/solutionDefinition"   xmlns:xhtml="http://www.w3.org/1999/xhtml"   publishUrl="http://myserver/events/solution.xsn">       <xsf:package>     <xsf:files>       <xsf:file name="template.xml"/>       <xsf:file name="schema.xsd"/>       <xsf:file name="paragraphs.xsd"/>       <xsf:file name="xhtmlType.xsd"/>       <xsf:file name="script.js"/>       <xsf:file name="helper.html"/>       <xsf:file name="default.xsl"/>       <xsf:file name="view2.xsl"/>     </xsf:files>   </xsf:package>       <xsf:fileNew>     <xsf:initialXmlDocument caption="Event" href="template.xml"/>   </xsf:fileNew>       <xsf:documentSchemas>     <xsf:documentSchema location="schema.xsd"/>   </xsf:documentSchemas>       <xsf:scripts language="jscript">     <xsf:script src="/books/2/633/1/html/2/script.js"/>   </xsf:scripts>       <xsf:taskpane caption="Form Entry Tips" href="helper.html"/>       <xsf:views default="Event Form">     <xsf:view name="Event Form">       <xsf:mainpane transform="default.xsl"/>       <xsf:toolbar caption="Views" name="switcher">         <xsf:button name="SwitchToPreview" caption="Preview This Event"/>        </xsf:toolbar>       <xsf:menuArea name="msoStructuralEditingContextMenu">         <xsf:button action="xCollection::insertAfter"                     xmlToEdit="pRepeating"                     caption="Insert Paragraph Below"                     showIf="immediate"/>         <xsf:button action="xCollection::insertBefore"                     xmlToEdit="pRepeating"                     caption="Insert Paragraph Above"                     showIf="immediate"/>         <xsf:button action="xCollection::remove"                     xmlToEdit="pRepeating"                     caption="Remove Paragraph"                     showIf="immediate"/>         <xsf:button action="xReplace::replace"                     xmlToEdit="single-to-multi"                     caption="Replace with All-day or Multi-day Event"                     showIf="immediate"/>         <xsf:button action="xReplace::replace"                     xmlToEdit="multi-to-single"                     caption="Replace with Single-day Event with Time"                     showIf="immediate"/>         <xsf:button action="xOptional::remove"                     xmlToEdit="end-time"                     caption="Remove End Time"                     showIf="immediate"/>         <xsf:button action="xOptional::remove"                     xmlToEdit="locationElement"                     caption="Remove Location"                     showIf="immediate"/>       </xsf:menuArea>       <xsf:editing>             <xsf:xmlToEdit name="pRepeating" item="xhtml:p" container="/event">           <xsf:editWith component="xCollection">             <xsf:fragmentToInsert>               <xsf:chooseFragment parent="description">                 <p xmlns="http://www.w3.org/1999/xhtml"/>               </xsf:chooseFragment>             </xsf:fragmentToInsert>           </xsf:editWith>         </xsf:xmlToEdit>             <xsf:xmlToEdit name="pRich" item="xhtml:p">           <xsf:editWith component="xField" type="formatted"/>         </xsf:xmlToEdit>             <xsf:xmlToEdit name="single-to-multi"                        item="single-day"                        container="event">           <xsf:editWith component="xReplace">             <xsf:fragmentToInsert>               <xsf:chooseFragment parent="when">                 <multi-day start-date="" end-date=""/>               </xsf:chooseFragment>             </xsf:fragmentToInsert>           </xsf:editWith>         </xsf:xmlToEdit>             <xsf:xmlToEdit name="multi-to-single"                        item="multi-day"                        container="event">           <xsf:editWith component="xReplace">             <xsf:fragmentToInsert>               <xsf:chooseFragment parent="when">                 <single-day date="" start-time=""/>               </xsf:chooseFragment>             </xsf:fragmentToInsert>           </xsf:editWith>         </xsf:xmlToEdit>             <xsf:xmlToEdit name="end-time"                        item="@end-time"                        container="event">           <xsf:editWith component="xOptional">             <xsf:fragmentToInsert>               <xsf:chooseFragment parent="when/single-day">                 <xsf:attributeData attribute="end-time" value=""/>               </xsf:chooseFragment>             </xsf:fragmentToInsert>           </xsf:editWith>         </xsf:xmlToEdit>             <xsf:xmlToEdit name="locationElement"                        item="location"                        container="event">           <xsf:editWith component="xOptional">             <xsf:fragmentToInsert>               <xsf:chooseFragment followingSiblings="when">                 <location/>               </xsf:chooseFragment>             </xsf:fragmentToInsert>           </xsf:editWith>         </xsf:xmlToEdit>           </xsf:editing>       <xsf:unboundControls>         <xsf:button name="btnCreate"/>       </xsf:unboundControls>     </xsf:view>     <xsf:view name="Preview Event">       <xsf:toolbar caption="Views" name="switcher">         <xsf:button name="SwitchToForm" caption="Go Back To Form"/>        </xsf:toolbar>       <xsf:mainpane transform="view2.xsl"/>     </xsf:view>   </xsf:views>       <xsf:customValidation>     <xsf:errorCondition match="single-day/@end-time"       expression="translate(.,':','') &lt;= translate(../@start-time,':','')">       <xsf:errorMessage type="modeless"                         shortMessage="End time must come after start time.">         The event's end time must be later than the event's start time.       </xsf:errorMessage>     </xsf:errorCondition>     <xsf:errorCondition match="multi-day/@end-date"       expression="translate(.,'-','') &lt;= translate(../@start-date,'-','')">       <xsf:errorMessage type="modeless"                         shortMessage="End date must come after start date.">         The event's end date must be later than the event's start date.       </xsf:errorMessage>     </xsf:errorCondition>   </xsf:customValidation>       <xsf:submit caption="Submit Event" showStatusDialog="no">     <xsf:useScriptHandler/>   </xsf:submit>     </xsf:xDocumentClass>

This form definition file illustrates a number of advanced features:

  • Support for multiple views in this case, the default view (default.xsl), which was shown in Example 10-15, and a secondary view (view2.xsl, not shown in this chapter)

  • The use of an HTML task pane (helper.html), shown later in Example 10-17

  • The declaration of a script file that uses JScript (script.js), shown later in Example 10-18

  • The declaration of custom buttons associated with structural editing actions

  • The use of custom validation rules over and above the XSD schema (using the xsf:customValidation element)

  • The declaration of a form submission mechanism whose behavior is defined by a custom script (using the xsf:useScriptHandler element)

All of these features and their corresponding XSF declarations are well documented in InfoPath's online Help system or secondary Microsoft documentation. For purposes of this tutorial, we'll take a closer look specifically at how structural editing actions are enabled.

10.4.4.1 Creating toolbars, menus, and buttons

To enable any structural editing action or a custom action, a button must first be created. The form definition file allows you to create custom toolbars that contain menus or buttons. Menus (described using the xsf:menu element), in turn, can contain buttons or more menus. The form definition file in Example 10-16 includes one custom toolbar declaration for each view. The declaration for the default view's custom toolbar is shown again below:

  <xsf:toolbar caption="Views" name="switcher">     <xsf:button name="SwitchToPreview" caption="Preview This Event"/>    </xsf:toolbar>

The button declared here is used to switch to the form's secondary view by invoking the OnClick handler for the named button, i.e., SwitchToPreview. The secondary view likewise has its own toolbar and button for switching back to the default view. See Example 10-18 for the script that contains the instructions that implement these actions.

In addition to custom toolbars, InfoPath contains nine built-in named menu areas:

msoFileMenu
msoEditMenu
msoInsertMenu
msoViewMenu
msoFormatMenu
msoToolsMenu
msoTableMenu
msoHelpMenu
msoStructuralEditingContextMenu

It should be obvious which menus in the UI each of these corresponds to. The last one, msoStructuralEditingContextMenu, is the only menu area used by our example solution, as declared in Example 10-16. This menu contains each of the buttons declared using the xsf:button declarations, shown again below:

  <xsf:menuArea name="msoStructuralEditingContextMenu">     <xsf:button action="xCollection::insertAfter"          xmlToEdit="pRepeating"          caption="Insert Paragraph Below"          showIf="immediate"/>     <xsf:button action="xCollection::insertBefore"          xmlToEdit="pRepeating"          caption="Insert Paragraph Above"          showIf="immediate"/>     <xsf:button action="xCollection::remove"          xmlToEdit="pRepeating"          caption="Remove Paragraph"          showIf="immediate"/>     <xsf:button action="xReplace::replace"          xmlToEdit="single-to-multi"          caption="Replace with All-day or Multi-day Event"          showIf="immediate"/>     <xsf:button action="xReplace::replace"          xmlToEdit="multi-to-single"          caption="Replace with Single-day Event with Time"          showIf="immediate"/>     <xsf:button action="xOptional::remove"          xmlToEdit="end-time"          caption="Remove End Time"          showIf="immediate"/>     <xsf:button action="xOptional::remove"          xmlToEdit="locationElement"          caption="Remove Location"          showIf="immediate"/>   </xsf:menuArea>

The structural editing context menu is what the user sees when he or she right-clicks a section that has structural editing actions enabled on it, or left-clicks the blue down-arrow icon that automatically appears at the top left corner of a section when the mouse hovers over it. The showIf attribute on each button declaration causes the button to be displayed in the menu only when the user's selection is in certain contexts. The showIf attribute has three possible values:

immediate
enabled
always

The value immediate (which is used in all the instances above) is the most restrictive of the three. If showIf="immediate", then the button will only be included in the menu when its associated editing action is immediately applicable to the user's current HTML selection. What is precisely meant by "immediately applicable" depends on the particular editing action. A value of enabled means that the button will be displayed only when it is enabled (not otherwise grayed out). A button is enabled not only when the editing action is immediately applicable to the user's selection, but also when the user's selection is some descendant of that immediately applicable context. Finally, a value of always means that the button will be displayed in the context menu at all times, regardless of the user's current selection and regardless of whether the button is enabled or disabled (grayed out).

Rather than associating itself by name with custom OnClick event handling script (as with the buttons for switching between views), each of the xsf:button elements above declaratively associates itself with an action of a built-in editing component (see Section 10.4.4.2), by way of the action attribute. The value of this attribute is the name of the editing component, followed by a scope operator (::), followed by one of the actions available for that editing component. The button must also associate itself with an actual node in the source document, that node's view in the HTML document, and a configured instance of the editing component. This is all done in a single swoop by referring, in the xmlToEdit attribute, to an xsf:xmlToEdit element declared under the xsf:editing element inside the view's configuration. Finally, the caption attribute's value is what the user actually sees when using these buttons.

10.4.4.2 Editing components

An editing component is a collection of actions for editing certain kinds of XML nodes. Each component is configurable in its own way. There are six kinds of editing components. Table 10-1 shows the name, purpose, and associated actions of each.

Table 10-1. The six editing components and their associated actions

Name

Purpose

Actions

xCollection

For a repeating list, or table, of elements

insert, insertBefore, insertAfter, remove, removeAll

xOptional

For optional elements or attributes

insert, remove

xReplace

For choice groups of alternative elements

replace

xTextList

For plain, bulleted, or numbered lists (also corresponds to a repeating sequence of elements)

split, merge, remove

xField

For text bindings, i.e. text boxes and rich text boxes

(none)

xImage

For embedded images

(none)


Before continuing, let me warn you that the next several paragraphs are rather dense. They are an attempt to succinctly cover a complex topic, i.e., how editing control associations (declared using xsf:xmlToEdit elements) are established. If you get tripped up on a single point, don't stop reading. Try to forge on through the examples in the following sections. Things may become clear in retrospect. Most likely, they will only truly become clear after doing some experimentation of your own. In any case, this should get you started on the right track.

Each xsf:xmlToEdit element within the xsf:editing element in a view's configuration represents an XML editing control. It defines an association between nodes in the source document and a particular editing component, along with parameterization of the editing component's behavior.

The item and container attributes on each xsf:xmlToEdit element together define where the control is in the HTML editing view, by way of the structural and/or text bindings to XML source nodes that have already been established. The basic syntax is like this:

<xsf:xmlToEdit name="someID" item="pattern" container="pattern"...>

The required name attribute of the xsf:xmlToEdit element is a unique identifier and is what xsf:button elements refer to in their xmlToEdit attributes. The item attribute is always required, regardless of which editing component is being associated. The container attribute is only required for certain editing components and optional for others. For example, it is optional for xField, but it is required for xCollection, xOptional, and xReplace. (The editing component in question is determined by the value of the component attribute of the xsf:editWith child element.)

Whereas the item and container attributes determine where the control is in the HTML editing view, the xsf:editWith child element defines what the editing control is and does: which editing component it uses (through the component attribute), and how that editing component is configured (through any additional attributes and child elements of the xsf:editWith element). The basic syntax is like this:

  <xsf:editWith component="xSomeComponent"...>     <!-- other child elements, depending on which component is being used -->   </xsf:editWith>

The xsf:xmlToEdit element's container and item attributes' values must lie in the subset of XPath syntax that corresponds to the syntax for XSLT patterns. In fact, they are interpreted in essentially the same way as XSLT patterns. The precise definition of a pattern's behavior, as found in the XSLT recommendation, is that:

A node matches a pattern if the node is a member of the result of evaluating the pattern as an expression with respect to some possible context; the possible contexts are those whose context node is the node being matched or one of its ancestors. http://www.w3.org/TR/xslt#patterns

A helpful way to think about how editing control associations occur is to consider the procedural task that InfoPath performs while the user is editing. At any given point while a user is editing, InfoPath must determine whether or not to activate an XML editing control based on the user's current HTML node selection. Its criteria for doing so depend on the item and container attribute values of the various xsf:xmlToEdit declarations in the form definition file.

Here goes. Starting with the current HTML node selection, InfoPath traverses the ancestor nodes (in reverse document order) until it finds an HTML node that is bound to an XML node that matches the item pattern of an xsf:xmlToEdit element in the current view's configuration. If the container attribute is also present on a candidate xsf:xmlToEdit element, then InfoPath continues to traverse the ancestors until it finds an HTML node that is bound to an XML node that satisfies the container pattern. Provided that InfoPath finds an item node (and a container node, when specified) that is bound to the current HTML selection or one of its ancestors, then the current selection will behave as declared within the corresponding xsf:xmlToEdit element. Namely, the actions of the associated editing component will be available, and the actions will behave as customized by the xsf:editWith element's additional attributes and elements.

Moreover, both the container and item HTML nodes are control-selectable, i.e., a dashed border appears around them when the mouse hovers over them, and they can be selected by the user. An exception to this behavior is when the container node binds to an element that is not normally selectable within the body of an HTML document. This is the case with many of our example's declarations, in which the container XML node, the root event element, maps to the editing view's root html element. Though the container HTML node (html) is not selectable in this case, its binding to a node in the XML source document is still a necessary (and sufficient) condition for the editing control association to take place. If it were not for the structural binding between event and html, most of our solution's editing controls would be disabled.

An optional viewContext attribute on the xsf:xmlToEdit element can be added if there exists more than one HTML binding to the same XML node. (We saw a facetious example of this back in Example 10-4.) In that event, the viewContext attribute can be used to disambiguate two controls (i.e., xsf:xmlToEdit elements) that have the same context (item and container attributes), by referring to the value of an HTML element's xd:CtrlId attribute value. Then an editing control with a particular viewContext will apply only to an HTML selection that not only falls within the context specified by the item and container attributes but also is, or is a descendant of, an HTML element whose xd:CtrlId attribute value equals the value of the viewContext attribute.

That's how these things behave in the abstract. If you didn't comprehend it all, don't worry. Taking a look at some concrete uses of the individual editing components in our example may help.

10.4.4.3 The xCollection editing component

The xCollection component is used to edit a repeating list of elements. In our example, the xhtml:p element is associated with the xCollection editing component in order to enable actions such as xCollection::insertAbove and xCollection::insertBelow. This declaration is shown again below:

  <xsf:xmlToEdit name="pRepeating" item="xhtml:p" container="/event">     <xsf:editWith component="xCollection">       <xsf:fragmentToInsert>         <xsf:chooseFragment parent="description">           <p xmlns="http://www.w3.org/1999/xhtml"/>         </xsf:chooseFragment>       </xsf:fragmentToInsert>     </xsf:editWith>   </xsf:xmlToEdit>

When a user clicks inside the HTML p element in the editing view, the above-declared XML editing control is activated, because the p element falls within the context defined by the item and container attributes. Specifically:

  • p is bound to the xhtml:p element in the source document, which of course matches this declaration's item pattern ("xhtml:p")

  • p has an ancestor HTML element that's bound to an XML node that satisfies the container pattern ("/event"), namely the final ancestor element, the html root element of the editing view.

The xsf:editWith element, besides specifying which editing component to use (xCollection), in turn uses the xsf:fragmentToInsert element and its child, xsf:chooseFragment, to specify what XML fragment to insert when a user invokes the xCollection::insert, xCollection::insertAbove, or xCollection::insertBelow actions. When the user pushes the Insert Paragraph Below button, for example, a new XML fragment will be inserted, namely an empty p element in the XHTML namespace. Where the fragment will be inserted is determined by the parent attribute of the xsf:chooseFragment element. Its value is an XPath expression that is evaluated in the context of the container node, i.e., using the container XML node as the context node. If the parent attribute is absent, then the fragment is directly inserted as a child of the container node. In other words, the parent attribute's value, when absent, defaults to ".". In our example, the parent attribute is present, and the XPath expression description is evaluated using the root element, event, as the context node, yielding the source document's description element. Therefore, the fragment to insert will be inserted as a child of the description element.

10.4.4.4 The xOptional editing component

The xOptional editing component corresponds to an optional element or attribute in the source document. Our example contains an optional location element and an optional end-time attribute. The declarations for each are very similar, both in the form definition file and in the XSLT stylesheet. In both cases, the stylesheet uses an xsl:choose statement to test for the presence of the optional node. If present, the stylesheet processes the node using xsl:for-each, thereby establishing a structural binding. But when the optional node is absent, it has no way of creating a binding to the node, as there is no way to bind to an XML node that does not yet exist in the source document. The solution around this is to create a placeholder link that refers to the XML fragment to insert via the xd:xmlToEdit attribute:

  <td colspan="2"       xd:xmlToEdit="locationElement" tabindex="0">     <xsl:text>Click here to add optional Location</xsl:text>   </td>

The optionalPlaceholder CSS class is declared in the HTML document head. The linking behavior of the placeholder element (a td in this case) is effected by using the CSS behavior, url(#default#xOptional), an InfoPath-specific property included in our optionalPlaceholder class. The xd:xmlToEdit attribute refers to the locationElement editing control in the form definition file:

  <xsf:xmlToEdit name="locationElement"                  item="location"                  container="event">     <xsf:editWith component="xOptional">       <xsf:fragmentToInsert>         <xsf:chooseFragment followingSiblings="when">           <location/>         </xsf:chooseFragment>       </xsf:fragmentToInsert>     </xsf:editWith>   </xsf:xmlToEdit>

The above blurb shows that the fragment to insert when a user invokes the xOptional::insert action is simply an empty location element. The followingSiblings attribute on the xsf:chooseFragment element is necessary, because our schema dictates that the location element, if present, must come before the when element. Otherwise, the default insertion behavior would yield an invalid document. The default insertion behavior is to append the fragment as the last child of the parent node (the event element in this case, because the parent attribute is absent). The followingSiblings attribute can be used to override this default append behavior. Its value is an XPath expression evaluated in the context of the parent node (the event element, in this case). The effective behavior is that the fragment will be inserted before all the nodes in the node-set returned by the followingSiblings expression. In this case, that means the location element will be inserted immediately before the when element.

The end-time control declaration shows how attributes are inserted, using the xsf:attributeData element:

  <xsf:xmlToEdit name="end-time"                  item="@end-time"                  container="event">     <xsf:editWith component="xOptional">       <xsf:fragmentToInsert>         <xsf:chooseFragment parent="when/single-day">           <xsf:attributeData attribute="end-time" value=""/>         </xsf:chooseFragment>       </xsf:fragmentToInsert>     </xsf:editWith>   </xsf:xmlToEdit>

10.4.4.5 The xReplace Editing Component

The xReplace editing component is usually used in conjunction with a choice group in the schema between two or more alternative XML elements. In our example, the XSLT stylesheet initially establishes a structural binding by applying templates to the child of the when element, regardless of which element (single-day or multi-day) is present:

  <tr>     <td>When:</td>     <td>       <xsl:apply-templates select="when/*"/>     </td>   </tr>

The matching template rule is applied, thereby establishing a structural binding between the single-day or multi-day element and the div element contained within the matching xsl:template element, which will be one of these:

  <xsl:template match="single-day">     <div>       ...     </div>   </xsl:template>       <xsl:template match="multi-day">     <div>       ...     </div>   </xsl:template>

The form definition file in turn declares two separate editing controls, one for each possible element:

  <xsf:xmlToEdit name="single-to-multi"                  item="single-day"                  container="event">      <xsf:editWith component="xReplace">        <xsf:fragmentToInsert>          <xsf:chooseFragment parent="when">            <multi-day start-date="" end-date=""/>          </xsf:chooseFragment>        </xsf:fragmentToInsert>      </xsf:editWith>    </xsf:xmlToEdit>        <xsf:xmlToEdit name="multi-to-single"                   item="multi-day"                   container="event">      <xsf:editWith component="xReplace">        <xsf:fragmentToInsert>          <xsf:chooseFragment parent="when">            <single-day date="" start-time=""/>          </xsf:chooseFragment>        </xsf:fragmentToInsert>      </xsf:editWith>    </xsf:xmlToEdit>

As can be seen above, the xReplace component is configured in a similar way to the xOptional and xCollection components. It too uses the xsf:chooseFragment element to determine exactly what to replace the element with. In this case, the single-day element is replaced with a multi-day element that includes its two (required) empty attributes, and the multi-day element is replaced with a single-day element whose optional end-time attribute is absent.

10.4.4.6 The xField editing component

xField is the editing component that lets you customize the behavior of leaf node editing, or what we have been calling "text bindings". Our form definition file associates the xhtml:p element with the xField component so that it can customize its behavior specifically by declaring type="formatted" on the xsf:editWith element, effectively making the text binding behave as a rich text binding:

  <xsf:xmlToEdit name="pRich" item="xhtml:p">     <xsf:editWith component="xField" type="formatted"/>   </xsf:xmlToEdit>

The other legal values for the type attribute (when the component is xField) are plain, plainMultiline, formattedMultiline, and rich.

This example illustrates the fact that the same node in the source document can be associated with multiple editing components, since the form definition file also associates xhtml:p with the xCollection editing component. Another common use case for associating an element with multiple editing components is when an optional node can be removed (using xOptional::remove) or replaced (using xReplace::replace). In that case, two separate xsf:xmlToEdit declarations are necessary, one for xOptional and one for xReplace.


The xField component also supports the use of the proofing and autoComplete attributes on xsf:editWith. The value of these attributes (yes or no) determines whether the given field will enable the proofing features (such as spell checking), and form field auto-completion, respectively.

10.4.4.7 The xTextList editing component

Although our example doesn't use the xTextList editing component, it turns out that it probably should. As useful as xCollection is in other contexts, it doesn't make editing paragraphs as easy as you might expect from a Microsoft product. In Word, for example, to create a new paragraph or split an existing paragraph in two, you simply hit Enter. And to merge paragraphs, you just hit the Backspace or Delete keys, depending on where the current insertion point is. Thankfully, in InfoPath, you can use the xTextList editing component to expose this split-and-merge behavior that the user expects. This is much better than forcing the user to switch back and forth between the keyboard and mouse, typing sentences and then clicking "Insert Paragraph Below," or copying and pasting from one paragraph into the other because xCollection doesn't automatically split or merge paragraphs.

So let's see what would be involved in updating our solution to use xTextList for paragraphs, rather than xCollection. The XSLT stylesheet and all files other than the form definition file can remain unchanged. All we need to do in manifest.xsf is delete all of the xCollection-oriented buttons, as well as the editing controls named pRepeating and pRich. In their place, we add the following simple declaration:

  <xsf:xmlToEdit name="pList" item="xhtml:p">     <xsf:editWith component="xTextList" type="formatted"/>   </xsf:xmlToEdit>

This single declaration does everything that we tried to achieve using the xCollection component, only better. No more buttons are necessary, because the split, merge, and remove actions are by default made available through the Enter, Backspace, and Delete keys. And a separate xField declaration is no longer necessary, because xTextList also supports the type attribute (with values of plain or formatted).

10.4.5 The HTML Task Pane

Our form definition file in Example 10-16 declared a custom HTML task pane:

  <xsf:taskpane caption="Form Entry Tips" href="helper.html"/>

Example 10-17 shows the contents of helper.html, our custom task pane document.

Example 10-17. The HTML task pane, helper.html
<html>   <head>     <style type="text/css">       body { font-family: Verdana; font-size: xx-small; }     </style>   </head>   <body>     <form name="finalForm" action="http://myserver/process-events/" method="post">       <input type="hidden" name="xml"/>     </form>     <h3>Form Tips</h3>     <ul>       <li>Hit CTRL-ENTER to open a new paragraph while typing the event description</li>       <li>Right-click any item to see available actions</li>       <li>Use CTRL-Z and CTRL-Y to undo and redo your changes</li>       <li>Navigate forward and backward through the form using the TAB and SHIFT- TAB keys</li>     </ul>   </body> </html>

This task pane displays some common InfoPath editing shortcuts for the user, such as hitting Ctrl-Enter to trigger the xCollection::insertAfter action, which in this case functions to create a new paragraph. However, there is also a hidden HTML form embedded in the document. This demonstrates just one possibility of how XML created by InfoPath could be submitted to a web application other than through the built-in declarative submission mechanisms. The form doesn't do anything by itself, but a script can be written to access it and submit it, as we'll see in Section 10.4.6. InfoPath's built-in HTTP submission mechanism only supports HTTP POST of text/xml content, but this form and the accompanying script used to populate and submit it generates an HTTP POST request with content of type application/x-www-form-urlencoded, with the value of the xml parameter being the XML document that was created. The advantage is that it can be integrated with an existing web application designed to work with HTML forms.

Submission of XML as content of type application/x-www-form-urlencoded, while useful as an example, is not generally advisable, because it only supports ASCII characters. For an application that requires international characters or any other character outside the ASCII range, you should use a different submission mechanism.


10.4.6 The Script File

Our form definition file in Example 10-16 declared a script file:

  <xsf:scripts language="jscript">     <xsf:script src="/books/2/633/1/html/2/script.js"/>   </xsf:scripts>

Example 10-18 shows the contents of script.js, our custom script file.

Example 10-18. The script file, script.js
function SwitchToPreview::OnClick( ) {     XDocument.View.SwitchView("Preview Event"); }     function SwitchToForm::OnClick( ) {     XDocument.View.SwitchView("Event Form"); }     function XDocument::OnSubmitRequest(eventObj) {     var xdoc = eventObj.XDocument;     try     {         var finalForm = xdoc.View.Window.TaskPanes(0).HTMLDocument.finalForm;             finalForm.xml.value = xdoc.DOM.xml;         doSubmitHTMLForm(xdoc);     }     catch (ex)     {         eventObj.ReturnStatus = false;          throw ex;     }         eventObj.ReturnStatus = true; }     function btnCreate::OnClick(eventObj) {     eventObj.XDocument.Submit( );  }     function doSubmitHTMLForm(xdoc) {     var taskpaneDoc = xdoc.View.Window.TaskPanes(0).HTMLDocument;     var finalForm = taskpaneDoc.finalForm;     var resultWindow = taskpaneDoc.open(                          "http://myserver/pleaseWait",                          "result","scrollbars=yes,menubar=yes," +                          "resizable=yes,location=yes,toolbar=yes,status=yes");     finalForm.target = "result";     finalForm.submit( );     resultWindow.focus( ); }

The functions defined in this short script file perform two primary tasks:

  • Switching between views

  • Submitting the created XML to a web server

The view-switching behavior is achieved by implementing the OnClick event handler for each of the two buttons that were declared in the form definition file, in Example 10-16. The "Preview Event" view (defined by the view2.xsl stylesheet, not listed in this chapter) declared one of these buttons, named SwitchToForm:

  <xsf:view name="Preview Event">     <xsf:toolbar caption="Views" name="switcher">       <xsf:button name="SwitchToForm" caption="Go Back To Form"/>      </xsf:toolbar>     <xsf:mainpane transform="view2.xsl"/>   </xsf:view>

To switch back to the default "Event Form" view (defined by default.xsl), the following single line of code is all that's needed:

  XDocument.View.SwitchView("Event Form");

When the user clicks the Go Back To Form button, the editing view switches back to the default form view that was displayed when the form was first opened.

There is one other OnClick event handler implemented in this script file:

function btnCreate::OnClick(eventObj) {     eventObj.XDocument.Submit( );  }

Unlike the view-switching buttons, this button (named btnCreate) was not declared in the form definition file but instead was declared directly in default.xsl (Example 10-15), identified by the value of its xd:CtrlId attribute:

  <input type="button" value="Submit Event" xd:Ctrl/>

To be successfully referenced, this button must also be declared within the xsf:unboundControls section of the form definition file, within the xsf:view element:

  <xsf:unboundControls>         <xsf:button name="btnCreate"/>       </xsf:unboundControls>

Clicking on this button causes the solution's submission mechanism to be invoked. The form definition file specifies that the submit action should, in turn, be handled by a custom script (as opposed to one of the other options, such as xsf:useHttpHandler or xsf:webServiceAdapter):

  <xsf:submit caption="Submit Event" showStatusDialog="no">     <xsf:useScriptHandler/>   </xsf:submit>

The XDocument::OnSubmitRequest event is fired when the user attempts to submit the form. Finally, our corresponding event handler populates the xml field in our HTML task pane's hidden form with the serialized XML document created by the user, and submits it to a web server. At this point, we are using Internet Explorer's HTML document object model API, accessible via the HTMLDocument property of the InfoPath TaskPane object:

  var taskpaneDoc = xdoc.View.Window.TaskPanes(0).HTMLDocument;

Though our HTML task pane did not show an example of it, it is also possible to do the converse, i.e., access the InfoPath object model from script embedded in an HTML task pane document.

The complete InfoPath object model is well documented in InfoPath's online Help system, under Table of Contents InfoPath Developer's Reference InfoPath Object Model Reference.


10.4.7 The Cabinet Manifest

When it comes time to deploy your solution, you have several deployment options:

  • Individually publish all of the form template files, including manifest.xsf, to a shared location or web server

  • Use InfoPath design mode's "Publish Form..." feature to create and publish a .xsn file (see "Publishing a Form from Design Mode" later in this chapter).

  • Use the makecab.exe utility to create a .xsn file at the command-line prompt

Example 10-19 shows a DDF ("diamond directive file") that can be fed to the makecab.exe utility (included with Windows 2000 and XP) to package up all the form template files into a single CAB file, named event.xsn.

Example 10-19. A cabinet file manifest for solution deployment, cab-manifest.ddf
.Option Explicit .Set CabinetNameTemplate=event.xsn .Set Cabinet=on .Set Compress=on     manifest.xsf default.xsl view2.xsl template.xml helper.html schema.xsd paragraphs.xsd script.js

This file is not part of the InfoPath form template. Rather, it just provides a way to package the form template files into a single .xsn file, without having to open the solution in design mode with all of the potential issues that can create. (See "Developing Solutions that Play Nice with Design Mode," later in this chapter.) It can be executed using this command:

makecab.exe /F cab-manifest.ddf

You should ensure that when you do publish your form template, regardless of the deployment method chosen, you publish it to the same location as listed in the publishUrl attribute of the form definition file's root element, xsf:xDocumentClass. Otherwise, InfoPath will refuse to open the form, complaining that it has moved from its original location. For more information on this topic, see Section 10.5.4, later in this chapter.



Office 2003 XML
Office 2003 XML
ISBN: 0596005385
EAN: 2147483647
Year: 2003
Pages: 135

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net