For this section, you want to have the code loaded into Flex Builder, and perhaps have these pages printed or displayed on a second monitor. The links to download the source files are provided in the Requirements section at the beginning of this article.
To import the source files into Flex Builder, use the File > Import menu item, select Flex Project, and then browse to the archive containing the project, XML_viewer.zip. Once imported, you should see the XML-viewer project in the Flex Navigator pane. Expand the folders to locate the source files in the src folder, and the source XML and graphics in the assets folder.
Main.mxml is the backbone of the application.
As with all MXML components, it begins with an XML declaration, followed by the
top-level element, which defines the application as a WindowedApplication (that is, an AIR application).
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
width="800" height="660"
xmlns:comp="*" xmlns:fmtComp="fmtComps.*"
creationComplete="srcData.send()"
paddingLeft="0" paddingRight="0"
paddingTop="0" paddingBottom="0">
The attributes contain some key information, including:
layout="vertical").width="800"
height="660").xmlns:comp="*"
xmlns:fmtComp="fmtComps.*").creationComplete="srcData.send()").
This part is crucial. It causes the XML file to be loaded, which in turn
triggers the formatting of the XML in the presentation window.The following snippet shows one of the few instances of
ActionScript in this application. It creates a container/variable to hold the
XML data (userManualObj).
Then it defines a function to load the XML data into the container. The XML
data comes attached to the event object, as event.result.
<mx:Script>
<![CDATA[
import mx.utils.ObjectProxy;
import mx.rpc.events.ResultEvent;
[Bindable]
private var userManualObj:ObjectProxy;
private function loadModelData(event:ResultEvent):void
{
userManualObj=event.result.UserManual;
}
]]>
</mx:Script>
Dataproviders to MXML components, defined later
in this application, bind to this container, so when the data loads into this
container, those components are updated accordingly, and that drives the entire
presentation of the XML content.
The following code defines an HTTP service that will be the
source of the XML data. This is the service that is called when the application
completes loading, as defined in the root element of the WindowedApplication.
The service retrieves the XML data from the file, the location of which in this
case is hard-coded ("assets/UserGuide.xml"). The result
causes the loadModelData function to be invoked (as defined in the earlier ActionScript), passing the
XML data retrieved as a result property to the event.
<!-- Set up the HTTP service from where we get the source XML data -->
<mx:HTTPService id="srcData"
url="assets/UserGuide.xml"
result="loadModelData(event)"/>
The following code defines the main container for the rest of the presentation objects. The attributes handle some of the formatting. For the sake of brevity, the obvious formatting codes will not be included in further descriptions.
<mx:VBox width="100%" horizontalAlign="left"
height="100%" paddingBottom="0" paddingLeft="0"
paddingRight="0" paddingTop="0">
The following line defines the top-level tabnavigator,
which is used in this example to provide a way to navigate between top-level
elements of the XML (the troubleshooting section and the model descriptions):
<mx:TabNavigator width="100%" height="100%"
This application makes frequent use of the Repeater component, as a way to match and enumerate through all the children of an
element:
<mx:Repeater id="modelsRep" dataProvider="{userManualObj.Product.Model}">
The dataProvider binds to all the children of userManualObj.Product of element type Model, creating an array containing pointers to Model elements. With each pass through the Repeater, the variable modelsRep points to one of those Model elements.
With each pass through the Repeater, a VBox is created. In effect, this creates a tab for each Model element (remember
the Repeater is inside a TabNavigator). The label (title) of the
tab (VBox) is mapped to the Name child element of the currentItem of the Repeater.
This populates the title of the tab with the model name.
<mx:VBox label="{modelsRep.currentItem.Name}" width="100%" height="100%">
<comp:ModelDesc model="{modelsRep.currentItem}"/>
</mx:VBox>
While still inside the VBox, you call on
another component of the application, ModelDesc, passing to
it the currentItem:
<comp:ModelDesc model="{modelsRep.currentItem}"/>
This component will populate the VBox with the
rest of the content of the currentItem. After the Repeater handling the Model elements, but still inside the TabNavigator, you add
another tab (VBox) for the Troubleshooting section:
<mx:VBox label="Troubleshooting" width="100%" ...>
<comp:Troubleshooting issues="{userManualObj.Product.Troubleshooting.Issue}" />
The issues argument is passed to the Troubleshooting component. It contains an array of pointers to Issue elements that are
children of the Troubleshooting element.
</mx:TabNavigator>
</mx:VBox>
</mx:WindowedApplication>
And that's all there is to the Main.mxml. Having populated the tabs with content, the application then gives the user the tabbed UI, scroll bars, and so on for navigating around the content.
ModelDesc.mxml is a component designed to control the layout
and format of the contents of a Model element. It is called inside the
main Repeater in Main.mxml.
Here is the only other instance in which ActionScript is used in this application—to create a way to pass arguments to components. In this case, the argument will hold a pointer to a model element.
<mx:Script>
<![CDATA[
[Bindable]
public var model:Object;
]]>
</mx:Script>
Three VBox containers inside a TabNavigator create
three tabs to hold the content for each model (Overview, Instructions,
and Details):
<mx:TabNavigator width="100%">
<mx:VBox label="Overview" width="100%" height="550">
<fmtComp:ModelHeader title="{model.Name}" picture="{model.Picture.Graphic.file}" />
<fmtComp:Section title="Description" body="{model.Description}" />
<fmtComp:Features features="{model.Features}" />
<fmtComp:ComplexSection title="Usage" body="{model.Usage}"/>
</mx:VBox>
<mx:VBox label="Instructions" width="100%" height="550">
<fmtComp:Instructions title="Operation" body="{model.Operation}" />
<fmtComp:Instructions title="Cleaning" body="{model.Cleaning}" />
</mx:VBox>
<mx:VBox label="Details" width="100%" height="550">
<fmtComp:ComplexSection title="Storage" body="{model.Storage}"/>
<fmtComp:Section title="Availability" body="{model.Availability}" />
<fmtComp:TableSect tableSect="{model.Parts}" />
<fmtComp:Section title="Warranty" body="{model.Warranty}" />
<fmtComp:DistiSect distis="{model.Distribution.Distributor}" />
<fmtComp:Section title="Compliance" body="{model.Compliance}" />
<fmtComp:ComplexSection title="Notes" body="{model.Notes}"/>
</mx:VBox>
</mx:TabNavigator>
Because the order of the immediate children of the Model element are known and appear once, it is easy to call components
to render each one. In some cases, there are specific components to handle
specific element types (for example, ModelHeader) but in
other places, components can be reused for different element types (for
example, Section and ComplexSection).
The remaining components of the viewer application contain
similar code and concepts to main.mxml and ModelDesc.mxml. The
following list details the components:
ModelHeader.mxml: ModelHeader is invoked by ModelDesc to display the model name and picture (references to both of these are passed
as arguments). The built-in MXML components for Label and Image are used to render the elements.
Note: Because the source document uses graphics files in the SWF format, the graphics could be more engaging than static pictures, containing animation, video, or interactivity, for example. Such rich assets could be added to the source document without any changes to the viewer application.
Label and Text to display headings and paragraphs, with a Repeater to enumerate
all the paragraphs in a section.fmtComp:zeroOrMoreParas is invoked to display
paragraphs that optionally may appear before the bulleted list. This component
is a wrapper for a simple Repeater. It is used here because using Repeater directly inside Features.mxml tends to always result in at least one
iteration. Unlike with ActionScript, there is no conditional in MXML (that is, if..then),
so this workaround is needed to produce the intended effect.
An HBox is used inside the Repeater to render a
bulleted list. The HBox contains two items: the bullet and a
paragraph.
ComplexSection.mxml is
called. It uses the zeroOrMore wrapper components as a workaround
to using Repeater components directly.Features.mxml, ComplexSection.mxml and ModelHeader.mxml, Instructions.mxml renders a series of numbered instructions. Note the use of text="{instrStepsRep.currentIndex
+ 1}" to generate and display the step number.TableSect.mxml is used
to render Parts tables. This component uses the DataGrid component to
render the table. This component is simple because Parts tables always have a
three-column layout.Repeater.Main.mxml,
and renders a list of topics, concerns, and actions using a Repeater.