By: Ben Forta
Technical Evangelist
Allaire Corp.
We all know and dearly love ColdFusion Studio (and its
little brother HomeSite). We all have favorite features,
we all have our own little tips, tricks, and settings, and
we all find ways to make it work as suits as best.
But what many of us don't know is just how extensible
and configurable ColdFusion Studio really is. And so in
this article I'd like to introduce you to one of the ways
to extend this product Tag Editors.
Note: Although I refer to "ColdFusion Studio," everything
covered in this article applies equally to HomeSite, ColdFusion
Studio, and the new JRun Studio.
Understanding Tag Editors
One of ColdFusion Studio's most powerful help features are
its tag editors. These are the little dialog boxes that pop
up when you right-click on a tag and select Edit Tag (or press
Ctrl-F4). An example of a tag editor is shown in Figure 1.

Figure 1: Tag Editors are one of the most powerful
ways to get help in Studio and HomeSite.
The beauty of tag editors is that they are not hard-coded
into the product; rather, they are created on the fly. When
a tag editor is to be displayed, its definition is read
from a special file, and Studio uses that information to
create the dialog. Those special files can be edited (or
created) as needed.
Installing Tag Editors
If you've ever downloaded a tag from the Developer's Exchange
(at http://devex.allaire.com/developer/gallery)
it may have come with a file with a VTM extension. That file
is the tag editor definition file, and it is installed simply
by placing it beneath the TagDefs directory (for ColdFusion
Studio 4.5, this is usually C:\Program Files\Allaire\ColdFusion
Studio 4.5\Extensions\TagDefs). When ColdFusion Studio needs
to display a Tag Editor, it automatically scans that directory
tree to find the appropriate VTM file.
How are VTM files associated with tags? By their names.
The VTM for the HTML <TABLE> tag is TABLE.VTM, and
the VTM for the CFML <CFQUERY> tag is CFQUERY.VTM.
(If you've ever right-clicked on a tag in ColdFusion Studio
only to find the Edit Tag option grayed out, it is because
no matching VTM file was found).
ColdFusion Studio comes with VTM files for all of the
standard HTML, CFML, and even WML tags. But if you write
your own tags or download third-party tags, ColdFusion Studio
won't be able to display a tag editor unless a matching
VTM file has been created and installed.
Understanding VTML
VTM files are created using a special XML-based language called
VTML (for Visual Tool Markup Language). Before you groan at
having to learn yet another language, let me assure you that
this one is easy to learn; if you can handle HTML and CFML,
you'll manage VTML just fine.
So, what exactly is VTML? Well, what HTML does for browser
display and CFML does for server-side processing, VTML does
for dialogs and visual tools. VTML is a tag-based language
that is used to define and create visual tool elements.
These elements include dialogs, fields, help text, file
browser and color selectors, and more.
The best part about VTML is that all the language documentation
comes with ColdFusion Studio. If you are running ColdFusion
Studio 4 or later (you should be), you even have tag editors
that fully support VTML.
The <CF_OutputRedirect> Tag
The best way to learn VTML is to use it, so we'll do just
that. <CF_OutputRedirect> is a custom tag that simplifies
output redirection. It is a very simple CF4-style tag that
lets you wrap any block of HTML or CFML and redirect the output
to an email message, a file, or a variable. (If you've ever
had to gradually construct variable contents or needed to
use loops and queries within a <CFMAIL> tag, you'll
love this one.)
For our discussion, the exact details of how the tag works
are unimportant; the tag syntax, however, is very important.
<CF_OutputRedirect> can be used in three ways:
- This first example redirects all output to an email
message:
<CF_OutputRedirect OUTPUT="email"
TO="ben@forta.com"
FROM="ben@forta.com"
SUBJECT="Redirection">
... text, HTML, and CFML goes here
</CF_OutputRedirect>
- This next example redirects all output to a file:
<CF_OutputRedirect OUTPUT="file"
FILE="C:\USER\dump.txt">
... text, HTML, and CFML goes here
</CF_OutputRedirect>
- This final example captures all output in a single variable:
<CF_OutputRedirect OUTPUT="variable"
VARIABLE="var">
... text, HTML, and CFML goes here
</CF_OutputRedirect>
We're not going to get into the workings of the tag itself
right now. Instead, we're going to build a tag editor for
this new custom tag.
Creating a VTM File
VTM files are plain text files, just like HTML and CFML files.
The file we're going to create is called CF_OUTPUTREDIRECT.VTM,
and it needs to be saved under the TagDefs directory (you'll
see a subdirectory called Custom there, which is a great place
to save your own custom VTMs).
Make sure you are using an empty file (if Studio used
a default template containing text, delete all text before
proceeding) and then type the following:
<TAG NAME="CF_OutputDirect">
</TAG>
The <TAG> tag is used to define the Tag Editor itself,
and all the elements that you provide to build the Tag Editor
must be enclosed within <TAG> and </TAG>. The
NAME attribute is optional, but it is good practice to use
it to specify the actual tag name as I have done above.
Next comes the actual definition, and this is made up
of several sections:
- <EDITORLAYOUT> defines the actual dialog and all
of its fields and controls.
- <ATTRIBUTES> defines the attributes that the Tag
Editor must be aware of (so that when you edit a tag all
the fields are populated with the existing values).
- <TAGLAYOUT> defines how text is written back into
the editor window (and back into your file).
All of these sections must be present for the Tag Editor to
work properly.
Creating the <EDITORLAYOUT> Section
<EDITORLAYOUT> is used to lay out the editor (pretty
intuitive, eh?). Start by entering the following text (make
sure it is between the <TAG> and </TAG> tags):
<EDITORLAYOUT HEIGHT="120" WIDTH="400">
</EDITORLAYOUT>
The HEIGHT and WIDTH specify the actual height and width of
the dialog you are creating. These attributes are optional,
but if you don't specify them, the dialog could end up looking
too big or too small. (Of course, you can right-click on <EDITORLAYOUT>
and select Edit Tag to display its tag editor).
Now that we've defined the tag editors's dialog box, we
need to populate it. There are two types of items that can
go into a layout:
- Containers used to create pages or panels within
a dialog.
- Controls the actual elements within a page or
panel.
It is important to note that containers are optional. If you
are creating a simple tag editor that uses no panes or panels
within it, containers are not needed, and you can use just
controls. But our tag editor needs a tabbed dialog with three
tabs, one for each of the OUTPUT types. This way the user
will be able to select the desired output type and then be
prompted for the appropriate data (for an example of this
type of dialog, see the tag editors for <CFFILE> or
<CFLOOP>). It is also important to note that something
(be it a container or a control) must be specified between
the <EDITORLAYOUT> tags or you'll generate an error
when you try to display the tag editor.
As our tag editor uses a tabbed dialog, the first thing
we need to do is create a container for the tabs. Type the
following code between the <EDITORLAYOUT> tags:
<CONTAINER NAME="MainTabDialog" TYPE="TabDialog" WIDTH="MAXIMUM" HEIGHT="MAXIMUM">
</CONTAINER>
This creates an empty container as seen in Figure 2. The NAME
attribute specifies the name of this container (every container
or control should have a unique name). The TYPE specifies
that this container is a tabbed dialog (other types include
TabPage, which we'll use in a moment), and the WIDTH and HEIGHT
attributes are set to MAXIMUM so that the tabbed dialog fills
the entire editor dialog.

Figure 2: Containers are special controls that contain
one or more other controls.
Now we need to create the actual tabs. Enter the following
code in between the <CONTAINER> tags:
<CONTAINER TYPE="TabPage" NAME="EMAIL" CAPTION="EMail">
</CONTAINER>
<CONTAINER TYPE="TabPage" NAME="FILE" CAPTION="File">
</CONTAINER>
<CONTAINER TYPE="TabPage" NAME="VARIABLE" CAPTION="Variable">
</CONTAINER>
The three containers each create a tab as specified by the
type. Each tab has a name that should match the value that
will be returned if that tab is selected (in our example,
it is the OUTPUT attribute's value). If the names do not match
the OUTPUT values, the wrong tab will be displayed when editing
code with the tag editor. The CAPTION attribute specifies
the caption to be displayed in the tab. Figure 3 shows you
what the dialog now looks like.

Figure 3: The TabPage container is used to create tabbed
dialogs.
Tip: ColdFusion Studio caches VTM files. If you are
working on a tag editor and need to keep testing it, you'll
need to empty the cache so that ColdFusion Studio rereads
the VTM file. You can do this in ColdFusion Studio 4.0.1
(or later) by pressing Ctrl-Alt-Shift-C. If you are using
an earlier version of ColdFusion Studio, you'll need to
quit and restart it (that's another reason to upgrade).
Next comes the controls themselves. Each form control
is specified using a <CONTROL> tag. There are 16 different
types of controls supported allowing you to use everything
from text fields to check boxes to color and font selectors
to SQL statement builders. We'll be using three of these
controls in our tag editor.
We'll start with the FILE tab as that one is simplest.
Type the following code between the <CONTAINER> tags
for the FILE tab (it's the second container in the above
set of three):
<CONTROL TYPE="Label" NAME="lblFile" WIDTH=60 RIGHT=10 DOWN=10 CAPTION="File:"/>
<CONTROL TYPE="FileBrowser" NAME="txtFile" WIDTH="MAXIMUM" ANCHOR="lblFile" CORNER="NE"/>
The first tag creates a label (a caption) as specified by
the TYPE attribute. The control is named in the NAME attribute,
the actual text is specified in the CAPTION attribute, and
the width is specified in the WIDTH attribute (in pixels).
The second control defines a file-browser field (one that
lets you enter text or click a file button that is automatically
displayed to the right of the field) as specified in the
TYPE attribute. The WIDTH is set to MAXIMUM so that the
field uses the rest of the available space.
This is where is gets interesting. To manage the placement
of controls, relative positioning is used. The first control
is placed 10 pixels from the right and 10 pixels down. The
second control is positioned next to the first control using
the ANCHOR attribute. ANCHOR specifies the name of the control
to be used for relative positioning, and ANCHOR="lblFile"
specifies that position is relative to the control named
lblFile. The CORNER attribute specifies the direction relative
to the ANCHOR. NE (or northeast) means relative to the top
right; SW (or southwest) means relative to the bottom left),
and so on. In our example, the txtFile field is positioned
NE of lblFile. The result is shown in Figure 4.

Figure 4: The Label control is used for captions. FileBrowser
is used for file specification and selection.
Note: Notice that <CONTROL> tag end with a slash:
/. This is the XML convention when tags have no matching
end tags. As there is no </CONTROL> tag used, the
<CONTROL> tag must be terminated with a /.
Each of the control types supports a unique set of options.
For example, the Label control supports alignment and transparency
attributes, while the FileBrowser control supports the optional
use of filters and other options. The simplest way to select
the options you need is to use the VTM tag editors. Figure
5 shows the tag editor for the FileBrowser control we just
created.

Figure 5: You can use VTMs to create VTMs.
The definition for the VARIABLE tab is very similar to
the FILE tab, except that it uses a TextBox TYPE to create
a text field instead of a file browser. Type the following
code between the <CONTAINER> tags for the VARIABLE
tab:
<CONTROL TYPE="Label" NAME="lblVariable" WIDTH=60 RIGHT=10 DOWN=10 CAPTION="Variable:"/>
<CONTROL TYPE="TextBox" NAME="txtVariable" WIDTH="MAXIMUM" ANCHOR="lblVariable" CORNER="NE"/>
The last tab to look at is the EMAIL tab. Type the following
code between the <CONTAINER> tags for the EMAIL tab:
<CONTROL TYPE="Label" NAME="lblFrom" WIDTH=60 RIGHT=10 DOWN=10 CAPTION="From"/>
<CONTROL TYPE="TextBox" NAME="txtFrom" WIDTH="MAXIMUM" ANCHOR="lblFrom" CORNER="NE"/>
<CONTROL TYPE="Label" NAME="lblTo" WIDTH=60 ANCHOR="lblFrom" CORNER="SW" DOWN=10 CAPTION="To:"/>
<CONTROL TYPE="TextBox" NAME="txtTo" WIDTH="MAXIMUM" ANCHOR="lblTo" CORNER="NE"/>
<CONTROL TYPE="Label" NAME="lblSubject" WIDTH=60 ANCHOR="lblTo" CORNER="SW" DOWN=10 CAPTION="Subject:"/>
<CONTROL TYPE="TextBox" NAME="txtSubject" WIDTH="MAXIMUM" ANCHOR="lblSubject" CORNER="NE"/>
This code should be pretty self-explanatory at this point.
The EMAIL tab has three fields, so six controls are used
three labels and three fields. All fields are of TYPE TextBox,
and all are anchored to their appropriate labels (just like
we saw before). But to stack the fields one per line (as seen
in Figure 6), the labels need to be anchored, too. The second
label, for example, is anchored to the label above it, and
the direction is specified as SW (southwest, the bottom left).
To space the lines out a bit, DOWN specifies that the control
should be placed 10 pixels away.

Figure 6: All controls must be anchored to each other
for complete control over alignment and spacing.
And that's the <EDITORLAYOUT> section.
Creating the <ATTRIBUTES> Section
When you right-click on a tag to display its tag editor, the
values currently used are displayed in their appropriate fields
ready for editing. This mapping of attribute to field control
is specified in the <ATTRIBUTES> section. Type the following
text after the </EDITORLAYOUT> tag:
<ATTRIBUTES>
<ATTRIB NAME="FILE" CONTROL="txtFile"/>
<ATTRIB NAME="FROM" CONTROL="txtFrom"/>
<ATTRIB NAME="OUTPUT" CONTROL="MainTabDialog">
<ATTRIBOPTION VALUE="EMAIL"/>
<ATTRIBOPTION VALUE="FILE"/>
<ATTRIBOPTION VALUE="VARIABLE"/>
</ATTRIB>
<ATTRIB NAME="SUBJECT" CONTROL="txtSubject"/>
<ATTRIB NAME="TO" CONTROL="txtTo"/>
<ATTRIB NAME="VARIABLE" CONTROL="txtVariable"/>
</ATTRIBUTES>
The entire set of attributes is enclosed within <ATTRIBUTES>
and </ATTRIBUTES> tags. Each attribute is specified
with an <ATTRIB> tag (again, note the trailing / when
</ATTRIB> is not used). <ATTRIB> takes two attributes,
the name of the attribute, and the control to associate it
with. So <ATTRIB NAME="FILE" CONTROL="txtFile"> instructs
the tag editor to take the value passed to the FILE attribute
and save it in the txtFile control. The OUTPUT attribute only
has three possible values. To restrict the valid values to
that known set, the <ATTRIBOPTION> tag is used
one for each value.
When the tag editor is displayed, any existing values
will be used. Attributes not present will be ignored, and
their controls will be empty, but any attributes present
will editable. In addition, the right tab will be selected
because the value of the OUTPUT attribute is saved to the
MainTabDialog control, which is the control that contains
the tab pages.
Creating the <TAGLAYOUT> Section
We're not done yet. Right now if you were to click Apply,
nothing would be written back to the editor window. The final
required section is <TAGLAYOUT>. This is used to define
the way text gets sent back to the editor when the tag editor's
Apply button is clicked. Here's the entire code block. Type
it in as shown. We'll analyze it next:
<TAGLAYOUT>
<WIZIF OPTIONLowerCaseTags EQ 'true'>
<WIZSET TAGNAME = 'cf_outputredirect'>
<WIZSET FILE = 'file'>
<WIZSET FROM = 'from'>
<WIZSET OUTPUT = 'output'>
<WIZSET SUBJECT = 'subject'>
<WIZSET TO = 'to'>
<WIZSET VARIABLE = 'variable'>
<WIZELSE>
<WIZSET TAGNAME = 'CF_OUTPUTREDIRECT'>
<WIZSET FILE = 'FILE'>
<WIZSET FROM = 'FROM'>
<WIZSET OUTPUT = 'OUTPUT'>
<WIZSET SUBJECT = 'SUBJECT'>
<WIZSET TO = 'TO'>
<WIZSET VARIABLE = 'VARIABLE'>
</WIZIF>
<WIZIF OPTIONLinearLayout EQ 'true'>
<WIZSET SpacingGap = ' ' >
<WIZELSE>
<WIZSET SpacingGap = Chr(13) & Chr(10) & ' ' >
</WIZIF>
<WIZIF MainTabDialog EQ 'EMAIL'><$${TAGNAME} $${OUTPUT}="$${MainTabDialog}"
$${SpacingGap}$${TO}="$${txtTo}"$${SpacingGap}$${FROM}="$${txtFrom}"$${SpacingGap}
$${SUBJECT}="$${txtSubject}"></WIZIF>
<WIZIF MainTabDialog EQ 'FILE'><$${TAGNAME} $${OUTPUT}="$${MainTabDialog}"
$${SpacingGap}$${FILE}="$${txtFile}"></WIZIF>
<WIZIF MainTabDialog EQ 'VARIABLE'><$${TAGNAME} $${OUTPUT}="$${MainTabDialog}"
$${SpacingGap}$${VARIABLE}="$${txtVariable}"></WIZIF>
</TAGLAYOUT>
The first thing you'll notice are tags like <WIZIF>
and <WIZSET>. These are very similar to ColdFusion's
<CFIF> and <CFSET> tags and work the same way.
CFML is processed by ColdFusion, WIZML (Wizard Markup Language
so named because it is used to create the Wizards in
Studio and HomeSite) is processed by ColdFusion Studio or
HomeSite.
The first block of code in the <TAGLAYOUT> sets
a set of sever variables. A checkbox in the ColdFusion Studio
Settings options (shown in Figure 7) allows users to specify
whether tags should be inserted in upper case or lower case.
When a tag editor writes text back to the editor, it should
honor this setting (although technically it does not have
to), but this does not happen automatically. You have to
make it happen. That setting is contained in the OPTIONLowerCaseTags
variable, which will be TRUE if tags are to be inserted
in lower case and FALSE if they are to be inserted in upper
case. The statement <WIZIF OPTIONLowerCaseTags EQ 'true'>
checks to see if OPTIONLowerCaseTags is TRUE (lower case),
and if so, it sets the variables with lower-case values.
The <WIZELSE> clause sets the same set of variables
to upper case. Once these variables are set, they can be
used to render the output, and upper- or lower-case text
will be displayed as appropriate.

Figure 7: The Settings dialog "Lowercase all inserted
tags" value can be accessed via the OPTIONLowerCaseTags
variable.
The next block of code is another conditional statement,
this time checking OPTIONLinearLayout. This contains the
value of the checkbox at the bottom of every tag editor,
which can be used to write out attributes on a single line
or on multiple lines. If OPTIONLinearLayout is TRUE, the
tag is to be written out on a single line and a space character
is used between each attribute. If it is FALSE, a new line
character is needed along with enough spaces to line up
the attributes properly.
This spacing, too, does not happen automatically. You
have to programmatically manage it yourself. The code creates
a variable named SpacingGap (it could be named anything
you wish) that contains the text to be used between attributes
based on the state of that checkbox. Now instead of hard-coding
spaces in between attributes, that variable can be used
to lay out the output correctly.
The last block of code writes the actual text back to
the editor. Depending on the tab selected, different attributes
need to be written. For example, the FILE attribute is only
written if the FILE tab is selected. It is not used by the
EMAIL or VARIABLE tabs. To conditionally write out the correct
attributes, a set of <WIZIF> statements are used.
(If this were a simple tag editor (without multiple tabs),
we would not have needed three <WIZIF> statements.)
The first statement <WIZIF MainTabDialog EQ 'EMAIL'>
checks to see if the EMAIL tab was selected, and so on.
Within each set of <WIZIF> tags, the appropriate
data is written out to the editor. Each block of text starts
with a < and ends with a > (the tag delimiters). Next
the tag name is written out using the variable $${TAGNAME}.
In WIZML, variables are referenced as $${var}. You can think
of $${ as the open # in CFML and } as the close #. $${TAGNAME}
writes out the text saved in the TAGNAME variable, either
upper or lower case as set earlier. Next comes a space,
followed by another variable (this time $${OUTPUT}, which
contains either the text "OUTPUT" or "output") and then
an equals sign followed by the $${MainTabDialog} within
quotes. You'll remember that MainTabDialog was the name
of the tab control created in the <EDITORLAYOUT> section.
$${MainTabDialog} contains the value of the selected tab
(EMAIL, FILE, or VARIABLE). Each attribute is then separated
by $${SpacingGap}, which was set in the <WIZIF> statement
above.
And that's all there is to it.
Conclusion
As you can see, creating your own tag editors is not an overly
complicated task. There have been lots of columns and articles
written on creating custom tags, and now you know how to polish
your tags by creating tag editors for them.
I have only covered the absolute basics of VTM, and there
is much more you can do (starting with the 13 other control
types and all their possible attributes). A good way to
learn VTML is to look at the VTM files associated with standard
tags (the HTML and CFML tags that Studio comes with). Pick
a tag editor that you use and see how it was created. There
is also a complete set of documentation right in the ColdFusion
Studio help system.
And there's even more. In a future article, I'll show
you how to write scripts that run right within the ColdFusion
Studio environment. Stay tuned.
About the Author
Ben Forta is Allaire Corporation's product evangelist
for the ColdFusion product line. Ben has over 15 years of
experience in the computer industry and spent 6 years as
part of the development team responsible for creating ONTime,
one of the most successful calendar and group scheduling
products, with over one million users worldwide. Ben is
the author of the popular The ColdFusion 4.0 Web Application
Construction Kit (now in its third edition) and the
more recent Advanced ColdFusion 4.0 Application Development
(both published by Que). He co-authored the official
Allaire ColdFusion training course, writes a regular column
on ColdFusion development, and now spends a considerable
amount of time lecturing and speaking on ColdFusion and
Internet application development worldwide. Born in London,
England, and educated in London, New York, and Los Angeles,
Ben now lives in Oak Park, Michigan, with his wife Marcy,
and their four children. Ben welcomes your email at ben@forta.com
and invites you to visit his own ColdFusion Web site at
http://www.forta.com/cf