Tuesday, November 29, 2005

DHTML II: Using Hidden Divs instead of Popup windows

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/dhtml_ii_using_hidden_divs_instead_of_popup_windows.htm]

Previous on DHTML: DHTML I: Intro and Positioning Text

A common UI problem is wanting to display a small amount of information (like a date) that takes a big UI control to generate (like a calendar). The standard solution to this is to make some sort of sub-window where the user has as much real-estate as needed to get that information. Two ways to implement this are (1) a new browser popup window, (2) hidden divs.

Each has their own pros & cons. Popup windows are pretty standard and relatively cross-browser dependable. Recall that you can open a popup like so:

window.open("Window.aspx","Name1",'toolbar=no,location=no ...');

Popup windows have several disadvantages:

  • It's hard to get data to and from them (you can pass data to them through the querystring, and from them with the window.opener property, but this is messy).
  • You can't control where the user drags them. They can hide them behind other windows, move them all over, max or min them, etc.. To some extent you can pile on the JavaScript to minimize what the user can do, but it gets tedious.
  • They open up a whole separate application (i.e. a new browser)

A whole different solution is to use a hidden div, and perhaps enclosing an iFrame to present a whole new page. This gives you the benefits of a popup (more temporary real-estate), without the drawbacks.

We can implement this using CSS's visibility style, along with the positioning attributes. Here's a sample how:

<html>
  <head>
    <title>SimplePopuptitle>
    <style>
      .divAbsPosition1
      {
        z-index: 1;
        left: 100px;
        position:absolute;
        top: 50px;
      }
    style>
  head>
  <body MS_POSITIONING="FlowLayout">
   
    <form id="Form1" method="post" runat="server">

    <div id="DivAbsPosition" class="divAbsPosition1" style="COLOR: black">
      <table border="1" bgcolor=#ffffcc>
        <tr>
          <td>Whatever content you want goes here.td>
        tr>
      table>
    div>
      <input type=button value="Show"
        onclick="document.getElementById('DivAbsPosition').style.visibility='visible'" />
      <input type=button value="Hide"
        onclick="document.getElementById('DivAbsPosition').style.visibility='hidden'" />
      <p>Some normal page content goes here.p>
      <p>Some normal page content goes here.p>
     form>
  body>
html
>

This technique is another great benefit of DHTML. It's very useful when writing your own custom control (such as a dropdown or calendar) or making appropriate popups.

Sunday, November 27, 2005

DHTML I: Intro and Positioning Text

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/dhtml_i_intro_and_positioning_text.htm]

HTML is essentially static. However with some JavaScript and CSS, you can make it dynamic - hence DHTML (D is for Dynamic). There are lots of neat things you can do with DHTML. While some of it may just be for "toys", some of it can also enhance the UI for an enterprise app.

Using CSS, you can position your text in several ways. First you can set whether the style refer to an absolute or relative position. You can then specify the left or top. You can also specify the "layer" via the Z index. For example, the following snippet offsets the div tag:

  <style>
    .pos1
    {
      z-index: 1;
      left: 100px;
      position:absolute;
      top: 20px;
      background-color:Yellow;
    }
  style>
  head>
  <body MS_POSITIONING="FlowLayout">
    <form id="Form1" method="post" runat="server">
      <div class="pos1">
      Hello World
      div>
     form>
  body>

You can use JavaScript to programmatically change the CSS class as whole, or switch a specific style:

document.getElementById('DivPosition').className = 'myNewClass';
document.getElementById('DivPosition').style.left = 10;

The combination of all these things opens up a lot of possibilities. For example, using a JavaScript timer, you could move a div across the page by continually updating the .left property.

The next several posts will dive more into DHTML.

Monday, November 21, 2005

Implementing a timer in JavaScript with setTimeout

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/implementing_a_timer_in_javascript_with_settimeout.htm]

Sometimes you want something cycling in the background to give your page an active feel, like images or text labels updating every 4 seconds. You can do that with the JavaScript setTimeout function. The script below keeps a running clock:

<html>
  <head>
    <script language=javascript>
   

    script>
  head>
  <body MS_POSITIONING="FlowLayout" onload="UpdateCycle()">
    <form id="Form1" method="post" runat="server">
      This is a timer test.
      <span id="Span1">span>
    form>
  body>
html
>

This method takes a method to call, and the time (in milliseconds) to wait. The pattern is simple:

  1. Have the body onload event call the looping function, like UpdateCycle(). This function manages the cycling.
  2. Have the looping function call whatever action you want, and the setTimeOut method.
  3. Implement the action method (in this case SetTime) to do whatever action you need.

You could even make a global variable, increment it in each UpdateCycle, and therefore keep a global counter of how many cycle have passed. You could also have the body onload call an initialization method instead, that method would do start-up initialization, and then call the UpdateCycle method.

This is a simple JavaScript method to use, but it can have a big return to help certain pages feel more lively.

Sunday, November 20, 2005

Setting the DOS ErrorLevel

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/setting_the_dos_errorlevel.htm]

Programs can return an errorLevel. Batch scripts can then access than using %ErrorLevel%, and then use this in the flow of the script. For example, if program X returns a certain errorLevel, the script can take a specific path. Convention is that an errorLevel of 0 is "Success", and anything else is some kind of failure.

This is not to be confused with creating an environmental variable named "ErrorLevel". Setting the environmental variable does not update the batch script's error level itself. This becomes apparent when using another tool that checks the script errorLevel. For example, in NAnt you can execute batch scripts and specify the build to fail if there's an error in the batch. However, you'll notice (at least in version .84) that setting the errorLevel as an environmental variable won't cause the script to fail, but having an exe fail will.

We want the option of setting the errorLevel from an environmental variable, not just through an exe. We can do this by writing a trivial console app:

[STAThread]
static int Main(string[] args)
{
      int i = 0;
      try
      {
         i = Convert.ToInt32(args[0]);
      }
      catch
      {
        Console.WriteLine("Error info...");
      }
      return i;
}

This takes a single argument from the command line, converts it to an integer, and then returns that value as the program error code. Note that console apps need not return "void", as is the template default. They can return int precisely for this purpose.

We can then call this program, passing in some parameter from DOS, and it will set the errorLevel. You'll notice that this would cause the NAnt build to fail. Also note that this call must be the every last line of the batch - not even an ECHO or REM after it.

Confusing the environmental errorLevel and DOS script's errorLevel is an easy and understandable mistake, and fortunately it has an easy and understandable solution.

Monday, November 14, 2005

Random DOS Nuances: for-loops, params, and if-blocks

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/random_dos_nuances_forloops_params_and_ifblocks.htm]

I've blogged some tips on DOS before, but here are some more. One of my coworkers (thanks Roey) pointed out several DOS nuances that I found useful - they're the kind of things that are easy to miss:

Use single % for parameters (like %1), double %% for variables (like %myVar%)

While you can use environmental variables using the percent signs like so: %myVar%, parameters only have the first percent, like so: %1. What's tedious is if you make it %1%, you may be able to get away with it in some cases. But if you put two parameters on the same like like %1...%2, then you need to get it straight.

Set operators within an if-block don't update until after the if-block finishes

In a language like C#, you could both update the variable, and then use that variable within the same if-block. Apparently you can't do that in DOS.

REM: Won't work:
If 0 EQU 0 (
    set outputFile="ABC"
    Echo Value: %outputFile%
)

You need to let the if-block finish first. You can do this by putting the set operation in its own block, either like this:

REM: WIll work:
If 0 EQU 0 (
set outputFile="ABC"
)
Echo Value: %outputFile%

or like this:

REM: will also work:
If 0 EQU 0 set outputFile="ABC"
If 0 EQU 0 Echo Value: %outputFile%

DOS for-loops in a batch script require an extra '%' in front of the variable.

This will fail:

Rem start loop:
for /F %a in (C:\temp\List.txt) do Echo %a
Pause

This will work:

Rem start loop:
for /F %%a in (C:\temp\List.txt) do Echo %%a
Pause

This last one is especially tedious to debug because if you copy the contents of the script to a command window to run it, then it suddenly works.
 

Thursday, November 10, 2005

Chicago .Net Launch

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/chicago_net_launch.htm]

I just got back from the Chicago .Net Launch, and it was very impressive. It looks like Microsoft is releasing new products for the entire enterprise spectrum. I'm especially interested in the new Visual Studio and Team System that finally makes it easy to build good development process, and the new features of ASP.Net. I also had some great experiences with the ask-the-experts. The Microsoft guys were on as usual, but the non-Microsoft experts were great too. In particular, Jon Henning of DotNetNuke nailed a bunch of my ASP questions. I also stopped at maybe 50 different vendor booths to see every kind of tool and service in the .Net ecosphere. A good day all around.

Tuesday, November 8, 2005

Making backups with the free RoboCopy

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/making_backups_with_the_free_robocopy.htm]

I had gotten an external harddrive to backup my laptop, but now I needed a way to copy only changed files. For example, if I have 5GB of files to backup, but perhaps only 10-100MB of new files each time I do the backup, for performance reasons I only want to copy the new stuff. Initially I thought "oh well, I'll just write my own program to do this", but then I realize that this is such a common task that there has to be free stuff out there (principle: don't reinvent the wheel). Someone pointed me to Robocopy, which you can download for free, along with 50+ other tools, as part of the Windows Server 2003 Resource Kit Tools.

Robocopy, for "Robust File Copy Utility ", is a command line tool for copying files from one location to another. It has all the switched that you'd expect: only copy changed files, ignore hidden files, number of times to retry copy a file if there are errors (such as a process locks the file and you can't copy it). It's a convenient thing. I created a batch script to do my master backup:

set USBdrive="E:\Tim_Main"
rem "C:\Ameripay" "%USBdrive%Tim_Main\Ameripay"

robocopy /S /R:2 /W:10 /XA:H "C:\Ameripay" "%USBdrive%\Ameripay"
robocopy /S /R:2 /W:10 /XA:H "C:\Development" "%USBdrive%\Development"
robocopy /S /R:2 /W:10 /XA:H "C:\Documents and Settings" "%USBdrive%\Documents and Settings"
robocopy /S /R:2 /W:10 /XA:H "C:\Inetpub" "%USBdrive%\Inetpub"
robocopy /S /R:2 /W:10 /XA:H "C:\Learning" "%USBdrive%\Learning"
robocopy /S /R:2 /W:10 /XA:H "C:\Projects" "%USBdrive%\Projects"

REM DONE!

Pause

I stored the target drive as an environmental variable, and then used the following options:

SwitchPurpose
/SCopy Subdirectories, but not empty ones.
/R:2Number of Retries on failed copies: default 1 million.
/W:10Wait time between retries: default is 30 seconds.
/XA:HDon't copy hidden files

There's tons of other switches to configure.

It's quick, yet extremely helpful if your main hard drive crashes.