Several people have asked about the status bar in my jQuery Photoalbum example I posted recently. This is nothing fancy at all and actually quite simple to do, but since several people have asked me I thought I'd discuss how it works. Although this solution uses jQuery it's easy enough to do something similar with plain DOM code or another JavaScript library - most of what makes this work is really CSS (and I suspect that's what some of the questions were really about), rather than any sort of client code, although the component I'll show at the end is a little more involved.

Why a Status Bar?

I find myself using Statusbars for information display in most of my administration pages and on occasion also in some main site front end pages. Like in desktop apps, once you start doing client side scripting using alert boxes for information gets to be a painful user interface practice and it's practical to use some consistent location to display all messages. For this task I like status bars either at the top or bottom of the page.

In the photo album application the status bar is used on the bottom of the page using fixed placement with some transparency so that the status bar is always visible but floats on top of all content:

StatusBar

When messages are sent to status bar they can be timed out so that the status bar reverts back to some default message (Ready typically). When a new message is assigned it's displayed in highlighted format:

StatusBarHighlight 

After the timeout is up the display reverts back the plain black and white formatting or rather the default styling defined via the statusbar CSS class.

You can see the status bar running in the sample photo album page:

http://www.west-wind.com/rick/photoalbum/demoMaui2006/default.aspx?Admin=true

Saving Changes and deleting images causes updates of the status bar (as well as any Ajax callback errors which hopefully shouldn't occur <g>).

Starting with CSS

What makes this work for the most part is CSS styling of the element. The statusbar is little more than a simple <div> tag with a CSS class applied. There are two classes that are used for the basic display; one for the base display and one for the highlight display that is used when a timeout is applied:

.statusbar
{
    position: fixed;
    bottom: 5px;
    left: 0px;
    right: 0px;
    height: 16px;    
    padding: 5px;
 
    background: black;
    color: white;    
    border: solid 1px lightgray;
 
    opacity: .70;    
    filter: alpha(opacity="70");
    z-index: 200;
 
    overflow: hidden;
    overflow-y: auto; 
}
.statusbarhighlight
{
    font-weight: bold;
    background-color: khaki;
    color: Maroon;
    border: solid 1px silver;
}

The key thing for the statusbar is the fixed positioning which puts the status bar on the bottom of the page and keeps it there regardless of scrolling the browser. I like to bump the status bar 5px above the window bottom and then use transparency to let the underlying content seep through, because any other content will flow underneath it. Unless you use a statusbar in a fixed container of some sort, I think this is a good idea to make it clear the status bar sits on top of content rather than denoting the absolute bottom of the page.

The highlight will be applied in addition to the statusbar class so the display for highlights effectively combines both styles. The highlight merely changes colors and border to highlight the statusbar text before the highlight is removed after a short timeout.

You can obviously change the CSS any way you like since it's only CSS so you can make the status bar display a square box rather than a strip on the bottom, or a bar running vertically down the right side. And that's the point anything goes.

Basic JavaScript jQuery Code

When I originally built the statusbar I just used a generic function that is quick and dirty. It basically creates a DOM element for the status bar on the fly and applies the appropriate classes. The function is very basic and hard codes a few things:

function showStatus(message,timeout,add)
{        
    if (typeof _statusbar == "undefined")
    {
       // ** Create a new statusbar instance as a global object
        _statusbar = 
            $("<div id='_statusbar' class='statusbar'></div>")
                    .appendTo(document.body)                   
                    .show();
    }
 
    if (add)              
       // *** add before the first item    
        _statusbar.prepend( "<div style='margin-bottom: 2px;' >" + message + "</div>")[0].focus();
    else    
        _statusbar.text(message)
 
    _statusbar.show();        
 
    if (timeout)
    {
        _statusbar.addClass("statusbarhighlight");
        setTimeout( function() { _statusbar.removeClass("statusbarhighlight"); },timeout);
    }                
}

With this function and the above CSS in place you can now from anywhere in your code issue:

showStatus("Photo Collection has been updated",5000);

Notice that there's also an add parameter which allows for cumulative entries where the data is added to the top of the div tag. This is useful if you want to use the status bar for outputting debugging messages and keep the list visible. For this to work you'd probably want to bump the height of the .statusbar class to 40px or bigger to see a few of the messages along with the scrollbars that let you scroll the list.

Note that you have a fair bit of control over where the statusbar goes and what it looks like via CSS. The dependency in this code is basically that a _statusbar global variable gets created and that you have to have .statusbar and .statusbarhighlight styles for the display to show the statusbar appropriately.

A more generic Statusbar Component

The basic code is OK and self contained, but it might be better to build a more generic component. Mind you this the following is a first cut. I haven't really gone through cleaning this code up or thought much about following the jQuery guidelines for plug-ins because in effect I prefer this to be callable via a single function, plus a single call for setup rather than as a jQuery utility function. In this sense this component is a little different than a typical jQuery plugin because it doesn't apply against a matched set of jQuery objects.

The generic version I built is basically a single class with a couple of methods. The idea is that you create an instance of the class somewhere in your startup code to configure it:

_statusbar = new StatusBar("#divStatus",
                           {showCloseButton: true, 
                            additive: true,
                            afterTimeoutText: "Click on caption to edit text..."});

from then on you can either use:

_statusbar.show("Images have been reloaded",5000);      
showStatus("Photo Collection has been updated",5000);

The latter is a utility function created that simply wraps the class by creating a global _statusbar variable using the default constructor and working off that. This is useful as it allows calling the function without any set up at all.

There's a bit more to this component in terms of configuration via properties. In jQuery fashion any of the properties can be optionally passed in via a options object map that defines any of the StatusBar properties to configure. For example, in the above I set three properties to allow the status bar to be closed, to show message additively so that there's a message history displayed and to have the text revert to a fixed caption after a timeout has fired.

Here's the source for the StatusBar object:

function StatusBar(sel,options)
{
    var _I = this;       
    var _sb = null;
 
    // options    
    this.elementId = "_showstatus";
    this.prependMultiline = true;   
    this.showCloseButton = false; 
    this.afterTimeoutText = null;
 
    this.cssClass = "statusbar";
    this.highlightClass = "statusbarhighlight";
    this.errorClass = "statuserror";
    this.closeButtonClass = "statusbarclose";
    this.additive = false;   
 
    $.extend(this,options);
 
    if (sel)
      _sb = $(sel);
 
    // create statusbar object manually
    if (!_sb)
    {
        _sb = $("<div id='_statusbar' class='" + _I.cssClass + "'>" +
                "<div class='" + _I.closeButtonClass +  "'>" +
                (_I.showCloseButton ? " X </div></div>" : "") )
                .appendTo(document.body)                   
                .show();
    }
    if (_I.showCloseButton)
        $("." + _I.cssClass).click(function(e) { $(_sb).hide(); });
 
 
    this.show = function(message,timeout,isError)
    {            
        if (_I.additive)       
        {
            var html = "<div style='margin-bottom: 2px;' >" + message + "</div>";
            if (_I.prependMultiline)
                _sb.prepend(html);
            else
                _sb.append(html);            
        }
        else
        {
 
            if (!_I.showCloseButton)    
                _sb.text(message);
            else
            {            
                var t = _sb.find("div.statusbarclose");                
                _sb.text(message).prepend(t);
            }
        }               
 
        _sb.show();        
 
        if (timeout)
        {
            if (isError)
                _sb.addClass(_I.errorClass);
            else
                _sb.addClass(_I.highlightClass);
 
            setTimeout( 
                function() {
                    _sb.removeClass(_I.highlightClass); 
                    if (_I.afterTimeoutText)
                       _I.show(_I.afterTimeoutText);
                },
                timeout);
        }                
    }  
    this.release = function()
    {
        if(_statusbar)
            $(_statusbar).remove();
    }       
}
// use this as a global instance to customize constructor
// or do nothing and get a default status bar
var _statusbar = null;
function showStatus(message,timeout,additive,isError)
{
    if (!_statusbar)
        _statusbar = new StatusBar();
    _statusbar.show(message,timeout,additive,isError);
}

The class provides the implementation and an optional static _statusbar instance is created to allow easy access to the object. If you don't you can use the showStatus() function implemented below which creates a default instance of the status bar and makes it work. Assuming you have styles configured for statusbar and statushighlight you'll get a status bar displayed according to your styling.

showStatus("Updated photo settings.",5000);

If you want to customize you can set the _statusbar instance explicitly using the configured constructor. Using the constructor allows you to override a few behaviors and it gives you a few more options in how the status bar displays:

  • Multi-line status display
  • Additive status messages with messages added top or bottom
  • Show an optional close 'button'
  • Ability to use custom CSS classes

To set this up you'd do the following in page startup code:

$(document).ready( function() {        
    if (serverVars.adminMode) 
    {        
        MakeListEditable();   
 
        var status = "Click on caption to edit text. Drag image to sort list..."
        _statusbar = new StatusBar(null,{showCloseButton: true, 
                                        additive:true,
                                        afterTimeoutText: status });
        _statusbar.show(status);      
    }            
} );     

You can pass options for customizing each of the StatusBar's properties using typical jQuery.extend() functionality where you can pass an object map of any of the StatusBar properties you want to override in the options parameter.

The additive feature allows you to display muliple status messages with messages appended to either the top or bottom (using the prependMultiline property). This allows for using the status bar as a debugging tool as well so you can write out status messages and avoid using alert() boxes as well. Here's what this looks like:

Multiline

You can have multiple status bars in a page as long as you create and hold on to multiple instances of the StatusBar object. For example you can have a display status bar and a debug status bar and even style them differently. A debug type output bar might be better served as a vertical bar on the left or right side of the browser for example and to do this you'd probably want to customize the CSS.

Note there are a few other components out there that provide debug output and if you are looking for some trace type output tool to help with debugging you're probably better off using one of these jQuery plug-ins. But if you're looking for a quick and dirty way to dump out messages to the screen in application or even library code the above approach works well because it can be done simply by adding a line of code with no further setup including in library code as long as the script is loaded.

From the Server side

Several people also asked how you can drive a jQuery component from the ASP.NET server side and the answer for simple things like this status bar is that you can simply inject the necessary JavaScript into the page via the ClientScript object (or ScriptManager if you're using MS AJAX). For example assume for a second that you'd like to set the initial status message that is displayed when the page loads from ASP.NET code you can use code like this to drive it:

protected void ShowStatus(string message, int timeout)
{
 
    var script =
@"
jQuery(document).ready( function() {{ 
var status = '{0}';
_statusbar = new StatusBar(null,{{showCloseButton: true,                                          
                            additive:true,                                        
                            afterTimeoutText: status}} );        
_statusbar.show(status,{1});
}});";      
 
    this.ClientScript.RegisterStartupScript(this.GetType(),
                      "showStatus",
                      string.Format(script, message, timeout), true);      
}

Then from anywhere in your page code:

this.ShowStatus("Click to start",0);

And voila you've got server Page interaction. Note that you'd want to remove the startup code from the script page though so that there won't be any jockeying for which message renders first. You'd have to make sure that the server ShowMessage is called at least once to ensure that an initial message is set and the _statusbar object set. If you'd use this functionality a lot you could wrap this up into a server control even and have a couple of properties that control the initial message and other options of the component to be set from the server side which would eliminate any special knowledge of for example having to set the initial display up front when not calling the ShowStatus method explicitly. Probably overkill for this simple component, but useful for more complex components.

As a jQuery Plug-in?

As mentioned this is a first cut of the refactored class and it probably needs a little more work to clean up a few odds ends. I am also trying to think of some ways to make this work more like a jQuery plug-in, but I can't think of a way that this would work effectively.

jQuery allows for utility functions on the jQuery static instance, but I don't think that the Statusbar class really makes a good fit as a static function/object since all it would do is add the $/jQuery prefix to the syntax. There's no benefit there that I can see. It also doesn't work well as a jQuery matched set operation function since the status bar is basically a static object - it's not operating against a matched set but always the same static object. In short, I think making this a jQuery plug-in would only complicate the component.

Anybody have any thoughts on this?

Anyway I hope this is useful to a few of you. I know I've been using statusbars in most of my applications for some time and this component makes the process for application level status displays very easy. I hope this has given you some ideas of how you can create a few helper functions/classes for your client code.

Download: wwjQuery.zip