HomeSite Help

VTML Tips and Techniques: Taglayout

 

We're moving!

This whole site is being moved to a shiny new server - as are all my sites, in fact. Apologies for the bumpy road ahead, but at the end of that road things will become fast and smooth.

Once the site at the new server is ready, this message will automatically disappear!

Meanwhile, you can see how the move is progressing at the status page.

 
   Home | VTML section | HTML section
On this page:
Small things: spaces
Expressions: more spaces
Number or String?
Where's the help?
What's in a TagName?
A case of case
Whitespace
Comments
Whitespace gobbler
(Vert)SpacingGap
Indent
Contributions!
 
 

Small things:
spaces

It's a matter of coding style really. But small differences in style can make large differences when you start using new tools. Look at the tag editors as they came with HomeSite: you'll find tags ending in " >" (a space before the closing angle bracket) all over the place, especially in WIZSET statements. I don't know where this style came from, maybe it's a common Cold Fusion style, or something inherited from Object Pascal? At first I thought it did sometimes help with readability, especially in those WIZSET statements.

Until I developed my VTML validation configuration file, that is. CSE HTML Validator is of course built to validate HTML, not VTML, so it has some sensible defaults. Like not allowing spaces at the start and end of tags, since this is really not allowed in HTML. There is a program setting to allow this, but it's easy to forget to toggle on and off when switching between validating HTML and validating VTML. So for all those tag editors, the program kept reporting all those spaces as errors.

Here's the good news: VTML does not need a space before a closing angle bracket, not even in WIZSET. So go ahead, use the Extended Search and Replace on the complete Template directory, and replace " >" by ">". No harm. No more toggling. No spurious errors when validating VTML. No skipping errors when validating HTML (when you forgot to toggle). Just a simple S & R, that's all. Instant new coding style.  to menu VTML Tips and Techniques


 

Expressions:
more spaces

More spaces, more coding style. When parsing expressions, the WIZML parser is perfectly happy to divide "i+1" into its three constituent parts: a variable name "i", an arithmetical operator "+" and a number "1". So what about "i-1"? Since dashes are allowed in variable names, it does not look like a numerical expression at all: it looks like a variable name: "i-1". And if it can't find a variable of that name, you'll get an error message.

Of course you can decide to write tight code, and only use spaces in expressions when they are really necessary not to confuse the parser. But then you'll be thinking about it all the time, and still be tripped up now and then. It's easier to follow just a simple rule: use spaces as delimiters around all operators in expressions.  to menu VTML Tips and Techniques


 

Number/String?

When is a variable a string and when is it a number? Wanting to generate LFWIDTH and LFHEIGHT attributes rather than have them defined by input fields posed an interesting challenge that answered this question as well. The answer is:
A variable is a number when you treat it as a number and it's a string when you treat it as a string. Too easy? I'll use my code generating LFWIDTH as an example to illustrate what happens:

First of all, the value you get from a TextBox (or DropDown) control obviously is a string. And when you write that out to a text file (like an HTML source file) it obviously is still a string, even if the string represents a number. So (in Editorlayout.vtm) WIDTH is a string entered in a control:

 
  
<CONTROL TYPE="TextBox" NAME="numWidth" WIDTH=30 ...
	
  

And I know there is a fixed proportion between the width needed for something in small fonts and the same thing used with large fonts. Can you take the string from the variable numWidth and use it as if it's a number in a numerical expression? Yes, you can:

<WIZSET LFWidth = (numWidth * 1.25)>
	

But what if the result is not an integer? Does the (LF)WIDTH attribute for a control take a broken number? A quick test showed it doesn't; somehow the control just takes on a default width which can make it run off the side of the window. So, I need to round the value resulting from my calculation. Alas, WIZML only has a set of string functions but no numerical functions.

Well, if I can take a string and treat it as a number, maybe I can take a number and treat it as a string? Yes, that works, too. The following bit of code determines whether there's a decimal point in the just-calculated variable LFWidth (and at what position). (If there isn't a decimal point, the next statement looks for a decimal comma.) If one is found, the digit to the right of it is used to decide to round up or down:

 
  
<WIZSET PosDecPt = Find(LFWidth,'.')>
<WIZIF PosDecPt EQ 0 AND Find(LFWidth,',')><WIZSET PosDecPt = Find(LFWidth,',')></WIZIF>
<WIZIF PosDecPt GT 0>
    <WIZIF Mid(LFWidth,PosDecPt + 1,1) GT 4>
         <WIZSET LFWidth = Left(LFWidth,PosDecPt - 1) +1>
    <WIZELSE>
         <WIZSET LFWidth = Left(LFWidth,PosDecPt - 1)>
    </WIZIF>
</WIZIF>
	
  

(With the introduction of VTML 2 and WIZML 2 with HomeSite and ColdFusion Studio 4.0, there are now two numeric functions as well. Now, you can write: <WIZSET LFWidth = Round(numWidth * 1.25)> - instead of the ten lines above. Or even just use that function directly in the output statement below. It would also prevent the extra statement I had to include to take care of the possibility of a decimal comma. For now, I'm not using these functions though, to keep my VTML Tag Definitions compatible with HomeSite 3.01 / ColdFusion Studio 3.11.)

Finally the result of the rounding (a number, of course), can be written to the target source document as a string:

 
  
<WIZIF 1>$$SpacingGap$${DefaultCase('LFWIDTH')}=$$LFWidth</WIZIF>
	

 to menu VTML Tips and Techniques

 
 

Where's the help?

In the Tagdescription section I've already mentioned the case of the disappearing tagdescription: In every single tag editor where I defined a tagdescription, it would result in the line with the buttons on the editor window; only in my TAG tag editor it did not appear. A big puzzle... Here's what happened and how I finally solved it:

I started writing the TAG tag editor using most of the techniques you find in the tag editors that come with HomeSite:

 
  
  • Assigning the tag name in upper or lower case to a variable of the same name as the tag:
    <WIZIF OPTIONLowerCaseTags EQ 'true'>
        <WIZSET TAG  = 'tag'>
        ...
    <WIZELSE>
        <WIZSET TAG  = 'TAG'>
        ...
    </WIZIF>
    	
  • Writing the start of the tag:
    <$${TAG}<WIZIF txtTagName NEQ ''>$${SpacingGap}...
    	
  • Writing the end tag, now followed by a tagdescription:
        <TAGLAYOUT SECTION="EndTag">
            <WIZIF OPTIONLowerCaseTags EQ 'true'></tag><WIZELSE></TAG></WIZIF>
        </TAGLAYOUT>
    
        <TAGDESCRIPTION HELPFILE="../Docs/VTMLTags/MKtag.html">
    
    </TAG>
    	
  

So why didn't the tagdescription appear? It took a long time before I saw what must be happening: while the WIZML processor (I'll call it that for lack of a better name) will happily execute the code in the EndTag section (it did work), the parser that reads the file to display it as an editor window will quite reasonably not read past </TAG> which indicates the logical end of the tag editor file. Have a look at this code again:

 
  
    <TAGLAYOUT SECTION="EndTag">
        <WIZIF OPTIONLowerCaseTags EQ 'true'></tag><WIZELSE></TAG></WIZIF>
    </TAGLAYOUT>

    <TAGDESCRIPTION HELPFILE="../Docs/VTMLTags/MKtag.html">

</TAG>
	
  

Guess which end tag the display parser stops reading at? Right, the very first one, which is the </tag> bit in the EndTag TAGLAYOUT section. It never even sees the TAGDESCRIPTION tag!

On to the solution in one small step and a few big jumps. The first step was to use the TAG variable that was also used to write the start tag; after all, we had already taken care of the difference between upper and lowercase tags:

 
  
<TAGLAYOUT SECTION="EndTag"></$${TAG}></TAGLAYOUT>
	
  

That this is possible is due to the fact that variables set in a previous TAGLAYOUT section (the StartTag section in this case) are available to later TAGLAYOUT sections. So there is no reason to to query OPTIONLowerCaseTags twice.
This solution worked, too: there are no longer three end tags for the TAG tag, and the tagdescription becomes visible.

The big jumps to the more generalized solution are explained below in What's in a TagName? and A case of case. If you look at the code for my TAG tag editor you can see it all put together in a small tag editor file. (The TAG tag editor is part of my package of VTML Tag Definitions which you can download from this site.)  to menu VTML Tips and Techniques


 

What's in a
TagName?

Part of what confused me in the case of the disappearing tagdescription described above was the fact that the tag name was assigned to a variable of the same name. It can make the code somewhat hard to read.

So I standardized: I chose a generic variable name: TagName and used that to assign the variable name to. Now this variable name does what a variable name should do: it describes the content (rather than reproducing it). It took a bit of work going through all the tag editors I was working on but it soon appeared to have a big advantage rather than just the logic of how to choose a variable name:

The code for writing an end tag now looked like this (note you don't need braces when writing a variable):

 
  
<TAGLAYOUT SECTION="EndTag"></$$TagName></TAGLAYOUT>
	
  

What I now had was a completely standardized bit of code for writing an end tag: I could now make a tag snippet of it. Nothing more needed than a double click when an end tag should be written in a new tag editor!  to menu VTML Tips and Techniques


 

A case of case

I think I was looking around for an example of WIZINCLUDE and found it in a Wizard file. Using the example, I soon found it didn't work in a tag editor. But in that very same Wizard file I found something else that was not documented but that did work: the function DefaultCase(). I've documented it in the MKfunctions.html file that is part of my set of VTML documentation files. What I'll do here is show how I'm using it in all of my tag editors - and why.

Consider what you have to do when adding a control for a new attribute to an existing tag editor:

  1. Add the control (usually preceded by a label) to the EDITORLAYOUT section and position it correctly;
  2. Create an ATTRIB tag for it in the ATTRIBUTES section;
  3. Create two entries for it in the TAGLAYOUT section to assign it to a variable: one in lower case and one in uppercase;
  4. Finally, ensure that it's written (at least when not empty) in the TAGLAYOUT section.

The first place where I applied the DefaultCase() function was for assigning the tag name to the now standardized TagName variable (see What's in a TagName? above); it worked quite well (from Tag.vtm):

<WIZSET TagName = DefaultCase('TAG')>
	

This proved that DefaultCase() did not only work in Wizards but in tag editors as well: it simply picks up the same variable (from the Registry) that is also used by OPTIONLowerCaseTags.

But what really bothered me was the two entries for very attribute assigning it to a variable in either lowercase or uppercase. It's maintenance intensive, and it's easy to forget altogether, or forget one of the two, or copy and paste and use the wrong case. Using the DefaultCase() function, I got rid of that section altogether. I'll use the TAG tag editor as an example again. Instead of:

 
  
<WIZIF OPTIONLowerCaseTags EQ 'true'>
    <WIZSET NAME        = 'name'>
    <WIZSET BODYEDITING = 'bodyediting'>
<WIZELSE>
    <WIZSET NAME        = 'NAME'>
    <WIZSET BODYEDITING = 'BODYEDITING'>
</WIZIF>
	

... and ...

<WIZIF txtTagName NEQ ''>$$SpacingGap$$NAME="$$txtTagName"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
<WIZIF checkBodyEditing EQ 'true'>$$SpacingGap$$BODYEDITING="Yes"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
	

... I now have only:

<WIZIF txtTagName NEQ ''>$$SpacingGap$${DefaultCase('NAME')}="$$txtTagName"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
<WIZIF checkBodyEditing EQ 'true'>$$SpacingGap$${DefaultCase('BODYEDITING')}="Yes"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
	
  

So for every new tag attribute there is now only one place it needs to be added to the TAGLAYOUT section: where the attribute is actually written. This means easier maintenance, faster construction of new tag editors, and fewer chances for making mistakes. That's why I've standardized on using DefaultCase().  to menu VTML Tips and Techniques


 

Whitespace

Handling whitespace in the TAGLAYOUT section can be tricky. The very first non-blank line that does not start with a WIZML tag will be written. If that's the start tag, the tag editor is clever enough not to consider the a blank line before it so you can start writing your start tag after a blank line for clarity. That's why HomeSite's tag editors start writing a tag like this - after a blank line but right at the start of the line (from the original A.vtm):

But after that first non-blank line, all white space around some "text" not enclosed in WIZML tags will be written. This can make it very hard to create a specific layout.

One little trick will help: If text is surrounded by a condition, and that condition evaluates to 'true', white space will be included only if it's within that same condition. As explained in my documentation for WIZIF (part of the package of VTML documentation that you can download from this site), when used as a condition a non-zero number evaluates to 'true'. So this is how I start writing the beginning of a tag:

Now that line is nicely indented with the rest but the tag will still be written at the current cursor position without worrying about unintended whitespace.  to menu VTML Tips and Techniques


 

Comments

As explained in Whitespace above, any text in a TAGLAYOUT section not enclosed in WIZML tags will be written out literally. So while you can use ordinary HTML comments in other sections of a tag editor, if you do that here the comment will be written out with the rest of the code. That's fine if you want to write a comment but if you only want to comment your code you'll have to prevent the comment from being written:

 
  
<WIZIF 0><!-- This comment will not be written --></WIZIF>
	
  

Just enclose the comment in a WIZIF condition that's always false!  to menu VTML Tips and Techniques


 

Whitespace
gobbler

The section Whitespace above explained how we can control unintended whitespace. But believe it or not, the WIZML processor also contains a whitespace gobbler. It lives in the EndTag section and can life make quite unpleasant if you're trying to control the layout of a tag that includes a tag body.

No matter what you do, any white space (spaces, tabs, newlines) written at the end of the previous section or at the start of the EndTag section is gobbled up: the end tag will appear right after the last non-blank character. It doesn't matter whether that white space is literal or contained in variables, it's eaten up anyway. But during that process, EndTag does something nice, too: it positions the cursor just before the end tag so you can just start typing from that position.

There is a solution to the behavior of the EndTag section: if you do all of the layout including the intended white space and writing the end tag from the StartTag section, layout can be precisely controlled. But you loose something in the process: the cursor will end up at the end of the end tag, instead of just before it.

As an illustration, here's the section of my TAGDESCRIPTION tag editor that actually does all the work; there's only a StartTag section here, no EndTag section: the end tag is written conditionally from the StartTag section as shown below:

 
  
<WIZIF 1><$$TagName</WIZIF>
<WIZIF txtHelpFile NEQ ''>$$SpacingGap$${DefaultCase('HELPFILE')}="$$txtHelpFile"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
<WIZIF txtHeight NEQ ''>$$SpacingGap$${DefaultCase('HEIGHT')}=$$txtHeight<WIZSET SpacingGap = VertSpacingGap></WIZIF>
<WIZIF TAGDATAUnknownAttributes NEQ ''>$$SpacingGap$$TAGDATAUnknownAttributes</WIZIF>
<WIZIF 1>></WIZIF>
<WIZIF txtHelpFile EQ '' AND txtBody NEQ ''>$$NewLine$$txtBody$$NewLine$$Tab</$$TagName></WIZIF>
	
  

Note how the HELPFILE attribute takes precedence over the tag body. But if no helpfile was specified and the tag body is not blank, the tag body is written followed by and end tag. Because the end ">" of the start tag is now no longer written at the end of the StartTag section, it's enclosed in a WIZIF that's always true so we can control whitespace. Then the tag body is written, starting with a new line (defined as Chr(13) & Chr(10)), and after that another new line followed by a tab (Chr(9)) and finally the end tag.

The result is a layout exactly as I want it - but the cursor ends up after the end tag.  to menu VTML Tips and Techniques


 

(Vert)SpacingGap

In some tag editors you'll see only the variable SpacingGap used for controlling whitespace within a tag, in others both VertSpacingGap and SpacingGap. So what's the difference?

 
  

Here's an example that uses only SpacingGap (Container.vtm):

<WIZIF OPTIONLinearLayout EQ 'true'>
    <WIZSET SpacingGap = ' ' >
<WIZELSE>
    <WIZSET SpacingGap = Chr(13) & Chr(10) & RepeatString(' ',(Len(TagName)+2))>
</WIZIF>

...

<WIZIF 1><$$TagName</WIZIF>
<WIZIF 1> $${DefaultCase('TYPE')}="$$containerType"</WIZIF>

<WIZIF containerType EQ 'TabPage'>
    <WIZIF txtName2 NEQ ''>$$SpacingGap$${DefaultCase('NAME')}="$$txtName2"</WIZIF>
    <WIZIF txtCaption2 NEQ ''>$$SpacingGap$${DefaultCase('CAPTION')}="$$txtCaption2"</WIZIF>
<WIZELSE>
    ...
	

And here's an example that uses both (Tag.vtm):

<WIZIF OPTIONLinearLayout EQ 'true'>
    <WIZSET VertSpacingGap = ' '>
<WIZELSE>
    <WIZSET VertSpacingGap = Chr(13) & Chr(10) & RepeatString(' ',(Len(TagName)+2))>
</WIZIF>
<WIZSET SpacingGap = ' '>

<WIZIF 1><$$TagName</WIZIF>
<WIZIF txtTagName NEQ ''>$$SpacingGap$${DefaultCase('NAME')}="$$txtTagName"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
<WIZIF checkBodyEditing EQ 'true'>$$SpacingGap$${DefaultCase('BODYEDITING')}="Yes"<WIZSET SpacingGap = VertSpacingGap></WIZIF>
<WIZIF TAGDATAUnknownAttributes NEQ ''>$$SpacingGap$$TAGDATAUnknownAttributes</WIZIF>>
	
  

In the first example, Container.vtm, the attribute TYPE is a required attribute. So right after the opening tag is written we can write out this attribute and know that only a space is required to separate it from the tag name. Any attributes written after that are separated by SpacingGap, which is either a space or or a newline and an indent - depending on the value of OPTIONLinearLayout.

In the second example, Tag.vtm, none of the attributes is required. Any non-blank attribute to be written could be the first one, so we can't just use a space: we'll have to use SpacingGap which still needs to be set to just a space the first time it's used. But any attribute written after the first (whichever is the first!) will need a SpacingGap determined by OPTIONLinearLayout. So for each attribute actually written, each of which could be the first, we'll have to set SpacingGap to the value of VertSpacingGap to control whitespace before any further attributes.

Also note the way the indent is defined: that's explained in the next section.  to menu VTML Tips and Techniques


 

Indent

If OPTIONLinearLayout is set to 'false' we have to line up tag attributes below each other, which means we need to indent every line written after the first. Of course you can just define the SpacingGap with a number of spaces, and count the spaces every time you create a new tag editor or clone one you already have for a new tag. What you need is one space for the opening angle bracket, then as many spaces as there are letters in the tag name, then one more space. But why count yourself when the computer can count for you?

My method is taking advantage of the fact that I've standardized on using TagName for holding the tag name to be written. I use two functions: RepeatString(), which repeats a string a given number of times; and Len() which looks at the length of the content of TagName - add two (opening bracket and extra space) and use the resulting number as the repeat for RepeatString():

 
  
<WIZSET SpacingGap = Chr(13) & Chr(10) & RepeatString(' ',(Len(TagName)+2))>
	
  

Now I never have to count anymore: the indent is standardized as well. Which means two more code blocks can become tag snippets that don't need any editing: the one with VertSpacingGaps and the one with only SpacingGap. And it's easy to clone a tag editor and create a new one from it; only the tag name which occurs only two or three times needs to be changed (with Replace, of course) but not the number of spaces for the indent.

These (and other) functions are documented in MKfunctions.html which is part of the package of VTML documentation that you can download from this site.  to menu VTML Tips and Techniques


 

Contributions!

Do you have any VTML Tips or Techniques to share? If it's for the Taglayout section, use the following email link, otherwise go to the page corresponding to the section it's about and use the Contributions! mail link from there, so your mail will have the correct subject.

Please explain why it's such a good tip, and illustrate with example code where appropriate. Also let me know whether you want you email address mentioned here, or only your name.

Send your contribution to: mail VTML Tips and Techniques Contributions

The VTML Tips and Techniques sections are:

 to menu VTML Tips and Techniques