Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

structuring an hta 2

Status
Not open for further replies.

ahogg

Technical User
Nov 4, 2003
13
TH
Hi,

This is a sort of "best practice" question. I'm developing an hta that manages a file system hierarchy (actually, it takes input for the user and generates a web page from that input).

I've structured it like this:

One table (2x2).
- first row devoted to cosmetic stuff
- second row:
1. menu: present all the time
2. content area

The menu allows the type of content the user is going to add, so I've been using the onclick event for each item in the menu to call a Sub that loads the contents of each module into the content area, but that means that all my code is concentrated in the .hta file and it's not very easy to maintain that way.

I'd like to have the code for each module in each separate page, but all the modules need access to some "global" variables, and I don't know how to get the modules to share these globals without being in the same script.

Thanks in advance!

Anthony
 
Maybe I'm missing something, but it seems to me that having a separate page/HTA for each module would involve quite a bit more effort to manage the code. Having it all within the same application seems far more intuitive. Then if you need to check the code you only have to scroll to the correct sub. I admit, having an HTA with several dozen different subs may look confusing to some, but I find it quite manageable by:

1. Commenting. Even if you don't comment on each line that actually does something, putting in a 2-3 lines of comments at the top of each sub indicating the general function, date of last change, etc is extremely helpful.

2. Whitespace. All of my subs are separated by 5 rows of whitespace, making it very easy to distinguish one from the next.
 
There are a number of possible strategies.

One is to simply keep the logic in one or more external .VBS files. This works for simple HTAs, but eventually you are once again faced with complexity.

In more complicated HTAs you may have any number of external ("dialog") windows, or multiple "panels" or frames. One way to handle this is to use conventional HTML frames. Another is to use iframes. In either case, the parent object can be useful.

Here is a trivial example, using <IFRAME> and parent:

main.hta
Code:
<HTML>
  <HEAD>
    <HTA:APPLICATION
      scroll="no">
    <STYLE>
      BODY       {background-color: #6666cc; margin: 0}
      IFRAME     {width: 100%}
      .clsHeader {background-color: #333399; text-align: center;
                  color: #ffffff; font-size: 120%}
      .clsNavBar {background-color: #ccccff; width: 120px;
                  vertical-align: top}
      .clsNav    {text-decoration: underline; color: #3333cc}
      .clsNavSel {text-decoration: underline; color: #ff6666}
      .clsPanel  {background-color: #ffcccc;
                  vertical-align: top}
    </STYLE>
    <SCRIPT language="VBScript" defer>
      'Define application globals.
      Dim lngTotal
      Dim strMessage

      Sub NavHiTest(ByVal N, ByVal Candidate)
        If N Is Candidate Then
          Candidate.className = "clsNavSel"
        Else
          Candidate.className = "clsNav"
        End If
      End Sub

      Sub NavHi(ByVal N)
        NavHiTest N, navFirst
        NavHiTest N, navSecond
      End Sub

      Sub navFirst_onclick()
        NavHi navFirst
        document.all.ifrPanel.src = "first.htm"
      End Sub

      Sub navSecond_onclick()
        NavHi navSecond
        document.all.ifrPanel.src = "second.htm"
      End Sub

      Sub window_onload()
        window.resizeTo 620, 220
      End Sub
    </SCRIPT>
  </HEAD>
  <BODY>
    <TABLE width="100%" height="100%">
      <TR>
        <TD colspan="2" class="clsHeader">
          Total: <SPAN id=spnTotal>0</SPAN>,
          Message: <SPAN id=spnMessage>*none*</SPAN>
        </TD>
      </TR>
      <TR>
        <TD class="clsNavBar">
          <DIV id="navFirst" class="clsNav">First Panel</DIV>
          <DIV id="navSecond" class="clsNav">Second Panel</DIV>
        </TD>
        <TD class="clsPanel">
          <IFRAME id="ifrPanel" frameborder="no" scrolling="no"
            application="yes" allowtransparency="true"
            src="none.htm">
          </IFRAME>
        </TD>
      </TR>
    </TABLE>
  </BODY>
</HTML>

none.htm
Code:
<HTML>
  <BODY bgcolor="transparent">
  </BODY>
</HTML>

first.htm
Code:
<HTML>
  <HEAD>
    <STYLE>
      BODY           {background-color: transparent;
                      margin: 0}
      INPUT#btnTotal {width: 60px}
    </STYLE>
    <SCRIPT language="VBScript">
      Sub btnTotal_onclick()
        With parent
          .lngTotal = .lngTotal + CLng(txtVal.value)
          .spnTotal.innerText = CStr(.lngTotal)
        End With
      End Sub

      Sub window_onload()
        txtVal.focus
      End Sub
    </SCRIPT>
  </HEAD>
  <BODY>
    <TABLE width="100%">
      <TR>
        <TD width="120">Value to add:</TD>
        <TD><INPUT type="text" id="txtVal"></TD>
      </TR>
      <TR>
        <TD></TD>
        <TD>
          <INPUT type="button" id="btnTotal"
            value="Total it">
        </TD>
      </TR>
    </TABLE>
  </BODY>
</HTML>

second.htm
Code:
<HTML>
  <HEAD>
    <STYLE>
      BODY             {background-color: transparent;
                        margin: 0}
      INPUT#txtMessage {width: 100%}
      INPUT#btnPost    {width: 60px}
    </STYLE>
    <SCRIPT language="VBScript">
      Sub btnPost_onclick()
        parent.spnMessage.innerText = txtMessage.value
      End Sub

      Sub window_onload()
        txtMessage.value = parent.spnMessage.innerText
        If txtMessage.value = "*none*" Then
          txtMessage.value=""
        End If
        txtMessage.focus
      End Sub
    </SCRIPT>
  </HEAD>
  <BODY>
    <TABLE width="100%">
      <TR>
        <TD width="120">Message:</TD>
        <TD>
          <INPUT type="text" id="txtMessage"
            maxlength="50">
        </TD>
      </TR>
      <TR>
        <TD></TD>
        <TD>
          <INPUT type="button" id="btnPost"
            value="Post it">
          </TD>
      </TR>
    </TABLE>
  </BODY>
</HTML>

Yes, this is probably more verbose than need be to illustrate the point.

The important thing is to look at the "global data" items declared in the script block in main.hta and the references to them via parent in both first.htm and second.htm.

This can give you good data encapsulation, code isolation, and general modularity by making the "panels" or frame pages separate. At the same time you still have access to global data or even object references.

If one wanted to go further, the script blocks could reference external .VBS files and the style blocks could be in separate .CSS files as well. Sometimes this is more pleasing to the "separate your presentation from logic" fans. Personally I think it's overkill for HTA development, though your mileage (and opinion) may vary.
 
Thanks a lot both of you,

kmcferrin, those are two guidelines that I follow, since they are not specific to VBscript in any way but to any source material. It is true that it helps mucho.

dilettante, that's exactly what I was getting at. Moreover, I'm one of those "separate your presentation from logic" fans, especially since the hta I'm writing now comprises over 700 lines of vbscript. So I'm already using a stylesheet and three hurrays to css.

Anyway, thanks again and good luck to you guys.
 
Oh man ahogg! You must be reaching for the antacid then when you examine my quick sample above. It has a wild mix of tables for layout and both inline attributes and CSS styles in use.

Sorry for that, it was quickly hacked together from existing HTM files and then tweaked on the fly... I agree, it is not an example of how to write good HTML.


But...

Did you spot the error?

Though I declared a global strMessage it never actually gets used! Instead, the spnMessage.innerText.value is being relied on as a data element and not just a display element.

This unintended gaffe just shows how easy it can be to sprinkle bugs through your code though.
 
I did notice, but I assumed it was I not looking right. Since I was after the specifics I didn't really dissect the code. Thanks again anyway, and btw, great tutorial too!

 
Hmmm. But what happens if you have something like this:

- main.hta

Code:
<html>
  <head>
    <script src="main.vbs"></script>
  </head>

  <body>
    <iframe id="editPanel"></iframe>
  </body>
</html>
and the code in main.vbs changes editPanel.src to the url of:

- page.htm
Code:
<html>
  <head>
    <script src="page.vbs"></script>
  </head>

  <body>
    <!-- ... -->
  </body>
</html>
Will the code in page.vbs be able to access variables in main.vbs? I'm supposing it won't. Is there any way to enable it? Or must I simply put everything global in main.hta and use With statements to get the juice?

Thanks again!
 
It should work just fine.

You don't have to use With blocks, you can just use parent.strMessage if you want to. It just saves on typing and can be a bit faster than refetching the object reference to the main page over and over again if you use it heavily.

I just wanted to be clear about the "bug" I had left in the example.


I'd like to see some other ideas on modularity in HTAs myself. This is just one that I've used from time to time.

The biggest challenge for me is avoiding having way-too-long .VBS files, yet I hate to break them up for performance reasons. One thing that I wish we'd had LONG ago is a VB5/6 style IDE for HTAs.

Even with the warts on IE's CSS support, a nice GUI designer based on CSS positioning could be a nice tool. I'd like to see one that offered 4 views of any "page" (HTA or HTM-in-a-frame):

1. Code view for script blocks - with coloring and IntelliSense.
2. GUI layout view.
3. HTML code view - with coloring and IntelliSense.
4. Preview view - with debugger.

I suppose a nice CSS editor would be great as well.


Most of my shorter HTAs I just whack out with NotePad. For bigger stuff I usually fall back on InterDev.
 
Hah. I agree. It seems that htas are a bit underplayed anyway. Hadn't even heard of them before last week...
 
dilettante,

I'm trying to use the parent property from within the iframe to access the variables in the document containing the iframe.

It's not working. The variable is declared in the main document as a global, and is called sCurrentProjectName.

From inside the iframe, the code I assume to be correct is:

Code:
parent.sCurrentProjectName = "blahblah"

but I get a runtime error telling me that there is no such property or method in the parent object.

Any idea what's going wrong?
Thanks in advance!
 
>Any idea what's going wrong?
Rename the main.hta to main.htm.

 
Hi Tsuji,

I don't think that will help really, since I do want to use a HyperText Application and not a website... Or am I missing something?

 
I'm not sure where tsuji is going with that myself.

Do you simply have a typo?

I tried adding that global and referencing it within an IFRAME script block. It worked fine.

Another thing you can do is put a VBScript [tt]Stop[/tt] statement just before the line that fails. This pops up a dialog asking whether or not to debug the script. I answer "yes" and then start probing using the "immediate" window in the debugger.

The exact details depend on which script debugger you have installed. I have InterDev, so that's what comes up ("Microsoft Development Environment"). You may have Windows Script Debugger or even the Office Script Editor set as your debugger.

You also need to have "disable debugging" options turned off in IE ("Internet Options" Advanced tab).

From there you can look at your code, set breakpoints, and try things like:

[tt]parent.sCurrentProjectName = "hi"
? parent.sCurrentProjectName[/tt]

The second one meaning "print" the value of the item. Don't type "print" because it'll try to print something on a printer you may not want (same as window.print I believe).

Of course that doesn't correct the error, but it may help track it down. If the "object" isn't valid you'll get the error back in the immediate window too when you try to assign it a value or print its value.
 
The point is hta and html behaves differently on many more aspects. If you rename your hta to html in your setting, it will show you that the reference to the parent global variable works out as expected. This articulates this particular aspect of the thing. If you still cannot get it shown, then your html/hta page has some syntactical problem in construction. So maybe rename for testing it out?
 
Okay, since you do not feedback or show a will to test you syntactical construction is errorless, I give you the solution.
[tt]
<iframe id="editPanel" [red]application="yes"[/red]></iframe>
[/tt]
 
Gosh tsuji, good catch.

I thought cross-frame scripting security violations gave a more explicit error message but I was wrong.

You're right, many of the scripting security rules differ for an HTA.
 
Hello dilettante, what is your normal working hours? I don't think you are on my part of the globe! Hope see you more here and with best wishes.
- tsuji
 
Wonderful!
Tsuji, I wasn't trying to offend, simply haven't been on the net since my last post. I hadn't noticed that attribute for the iframe. Thanks!

This is for whomever wonders what's happening here:

MSDN said:
APPLICATION
Indicates whether the content of the object is an HTML Application (HTA) and, therefore, exempt from the browser security model.
 
Hello to you too tsuji. Not to hijack the thread for personal communication, but...

My working hours are 8:00 to 5:00, GMT -5:00/-4:00 (U.S. EST/EDT). Somewhat irrelevant actually though, since I'm in a management role these days and hardly touch a computer except as an appliance (email, writing reports, etc.).

More typically I'd be posting here after normal working hours, related to a few side jobs I've been doing.

The result is that I don't get in here as much as in past years, and my posting level is down considerably as well. It is good to hear from you again as well though!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top