Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I specify the tab order in an HTA?

-- MJ

SpacerHey, Scripting Guy! AnswerScript Center

Hey, MJ. This is the time of year when the greatest and most-anticipated sporting event on the planet takes place, and we know that most of you are dying to hear what the Scripting Guy who writes this column has to say about that. Well, here’s what he has to say about that: he thinks you’d be crazy not to take part in the 2007 Winter Scripting Games.

What’s that? The Super Bowl? Sure, that’s OK … we guess. But unlike the 2007 Winter Scripting Games you’re not allowed to participate in the Super Bowl. And, as far as we know, the Super Bowl isn’t awarding out Dr. Scripto bobblehead dolls to 250 lucky winners, either.

And they call the Super Bowl a major sporting event. Ha!

At any rate, we hope you’ll enter at least one event in the Scripting Games; after all, that’s the only way to maybe get your hands on a Dr. Scripto bobblehead. (Dr. Scripto bobbleheads are not available in stores … probably for good reason.) With Advanced and Beginners divisions in both VBScript and Windows PowerShell this year’s Games have a little something for everyone. In fact, if you score at least 60 points in any one division you’ll receive a Certificate of Excellence signed by the Scripting Guys. Do you have any idea how much something like that is worth?

Well, true. But if you flip the thing over you can use the back as a piece of scratch paper.

As a warm-up for the Games let’s see if we can figure out how to modify the tab order in an HTA. To do so, we need to first take a look at a simple little HTA, one that features three text boxes and a button:

<html>
<head>
<title>HTA Test</title>
<HTA:APPLICATION 
     ID="objTest" 
     APPLICATIONNAME="HTATest"
     SCROLL="yes"
     SINGLEINSTANCE="yes">
</head>

<body>
    Box 1 <input type="text" name="BasicTextbox1" size="30"><P>
    Box 3 <input type="text" name="BasicTextbox3" size="30"><P>
    Box 2 <input type="text" name="BasicTextbox2" size="30" ><P>

    <input id=runbutton type="button" value="Run Script">
</body>

Onscreen this simple little HTA looks like this:

HTA


By default, tab order in an HTA is based on the location of the elements on a page; in this case, and assuming the cursor is in Box 1, the tab order is as follows:

Box 1

Box 3

Box 2

The Run Script button

Most of the time that’s going to be just fine. However, if you start using fancy, multi-column layouts you might not like the default tab order; for example, hitting the TAB key might cause the focus to move horizontally when you’d prefer that the focus move vertically. In our sample HTA, we’ve admittedly set up an unusual scenario: for demonstration purposes, we’ve placed Box 2 under Box 3. Ideally, if we have the cursor in Box 1 and we hit the TAB key we want the focus to move to Box 2 not Box 3. But, short of changing our layout, how can we do that?

Here’s how:

<html>
<head>
<title>HTA Test</title>
<HTA:APPLICATION 
     ID="objTest" 
     APPLICATIONNAME="HTATest"
     SCROLL="yes"
     SINGLEINSTANCE="yes">
</head>

<body>
    Box 1 <input type="text" name="BasicTextbox1" size="30" tabIndex=1><P>
    Box 3 <input type="text" name="BasicTextbox3" size="30" tabIndex=3><P>
    Box 2 <input type="text" name="BasicTextbox2" size="30" tabIndex=2><P>

    <input id=runbutton type="button" value="Run Script">
</body>

Sure, at first glance it doesn’t appear as though we’ve done anything. (Which, when it comes to the Scripting Guys, is usually a pretty safe assumption.) Ah, but take a closer look at our text box tags:

Box 1 <input type="text" name="BasicTextbox1" size="30" tabIndex=1><P>
Box 3 <input type="text" name="BasicTextbox3" size="30" tabIndex=3><P>
Box 2 <input type="text" name="BasicTextbox2" size="30" tabIndex=2><P>

There’s your answer right there, MJ. If we want to specify a particular tab order all we have to do is add the tabIndex property to our page elements and then number each element accordingly. With this revised HTA, and with the cursor in Box 1, pressing the TAB key will cause the focus to jump to Box 2; pressing TAB again will then cause the focus to jump back up to Box 3. Cool, huh?

You know, that’s a good question: what will happen if the cursor is in Box 3 and we press TAB? Well, in that case, we’ve cycled through all the items that have a specified tabIndex. Therefore, the focus moves to the first item that doesn’t have a tabIndex; in this example, that’s going to move the focus to the Run Script button.

Now, that might be good or it might not be good; after all, perhaps you don’t want the user to ever be able to tab to the button. That’s fine; all you have to do is add the tabIndex property to the button tag and set the value of tabIndex to -1:

<input id=runbutton type="button" value="Run Script" tabIndex=-1>

What’s the point of that? This is the point of that: items that have a tabIndex of -1 will be excluded from the tab order.

And yes, as a matter of fact you can programmatically assign and reassign the tab order. Why would you want to do that? Well, maybe you have a checkbox and, if the user checks the box, you’d like to tab them to a particular section of your HTA. If they don’t check the checkbox then you might want to tab them to a different section of the HTA. That’s fine; here’s a sample subroutine that – by setting the tabIndex to -1 – removes an element from the tab order:

Sub TestSub
    BasicTextbox2.tabIndex = -1
End Sub

To return the element to the tab order just assign a new value to the tabIndex. The nice thing here is that you can change the tabIndex property for one element without having to re-index all the other elements. For example, suppose you have items with tabIndexes of 1, 2, 3, 4, and 5. You run a script that sets the tabIndex of item 3 to -1; in effect, that removes this item from the tab order, and leaves you with tabIndexes of 1, 2, 4, and 5. Is that going to be a problem? Nope; if the cursor is in item 2 and you press TAB it will simply – and correctly – move the focus to item 4. The fact that there’s no item 3 won’t matter.

Note. Because of that, instead of numbering items 1, 2, and 3 you might number them 10, 20, and 30. That way you can easily insert a new item – say, 25 – without having to re-index everything.

And, of course, you can start your HTA with the focus on a particular element by using a Window_OnLoad subroutine and calling the Focus method:

Sub Window_OnLoad
   BasicTextbox1.Focus
End Sub

Nice.

In case you’re wondering, the Scripting Guy who writes this column did watch the Super Bowl; in fact, he always watches the Super Bowl. However, he doesn’t believe that the Super Bowl is the greatest and most exciting sporting event in the planet. Instead, that title is reserved for March Madness, the NCAA men’s basketball tournament. The fact of the matter is that nothing can come even close to matching the NCAA basketball tournament for sporting thrills and chills.

What’s that? World Cup soccer? No, we said greatest and most exciting sporting event. What does soccer have to do with sports?

Note. It’s up to you, but there’s probably no point in sending irate emails to the Scripting Guy who writes this column. After all, if he doesn’t like soccer by now he’s never going to like soccer. But don’t feel bad soccer fans: he doesn’t like hockey, boxing, car racing, the NBA, or rhythmic gymnastics, either.

And yes, we could go on and on. But, as a courtesy to our readers, we won’t.