Resize iframe Using jQuery on SharePoint

JavaScript to resize an iframe on a SharePoint custom page.

<script type=”text/javascript”>
// id = jQuery id of the iframe to auto resize.
// lessHeight = the amount in pixels to subtract from the browser window height when resizing the iframe.
// minHeight = the minimum height of the iframe.
function ResizeIFrame(id, lessHeight, minHeight)
{
var newHeight = window.document.body.offsetHeight – lessHeight;
var iframeHeight = (newHeight < minHeight) ? minHeight : newHeight;
$(id).height(iframeHeight);
}

// Register an iframe to be auto resized.
function ResizeIFrameRegistration(id, lessHeight, minHeight)
{
// Resize the iframe with the browser window is resized.
$(window).resize(function() { ResizeIFrame(id, lessHeight, minHeight); });
// Resize the iframe when browser page is finished loading and ready.
$(document).ready(function() { ResizeIFrame(id, lessHeight, minHeight); });
}

ResizeIFrameRegistration(“#<%= pdf.ClientID %>”, 250, 300);
</script>

JavaScript ASP.NET Rater control (Rating control): Sneak Peek

Rater Control, Rating Control, or 5-Star Rating Control, call it what you like.

I have created a new JavaScript ASP.NET Rater control (Rating Control). The entire functionality is driven by JavaScript, but I have also created an custom .NET control to facilitate easy use in an ASP.NET web application.  I intend on writing a much more detailed article, soon I hope.  For now you can see my demo page for a better look.

Technologies:

  • JavaScript
  • C#
  • ASP.NET

Here is a sneak peak at the Rater control in action: (Hint: use your mouse.)

Update: Sorry, the demo does not work on my new blog (WordPress), but the files are still available. :)

 

Download Files:

Note: For anyone who would like to link to my Rater control, please link to this post and not my demo page.  Thanks.  Also, I will make the C# source code for the .NET control available soon.

JavaScript Object Browser Sample

Note: This is a repost from my old blog:
http://blogs.crsw.com/mark/articles/652.aspx

Below is a small JavaScript application that allows you to browse through various objects on the DOM as well as JavaScript variables.  I wrote this in an attempt to better understand the differences between various web browsers, specifically Internet Explorer, Netscape, and Firefox.

Downloads:

– You can download my sample.

Demo:

Click here to view the demo page. (no longer active)

You will find a top level window object with all its immediate children located blow.  Links are available on child objects where appropriate.  This is 100% driven by looking at each object property generically, meaning, nothing is hard-coded.  This allows any of your custom JavaScript variables (in a Netscape browser its even better) to be viewed.

Areas I found of particular interest:

  • the windows.document node of the tree.
  • functions will appear with a function link.  Clicking on this link will reveal the JavaScript for that function.  My demo below will show the javascript by drilling into (clicking) on the window.document.onreadystatechange node.
  • the window.top.document.scripts link will list all the script tags, and the associated script if the actual script is embedded within the document.

I hope to improve and use this when debugging scripts.  Again, by adding two small links to javascript (via script tags) this becomes available on any page I like.

 

These javascript files are available for download (above) so that you can reference these files on your own server.

Below is a link to the demo, but FIRST, the remember to look at the root window node in the tree.  This will expand to show the context of the child items in the tree view.  For example, if you click on the document node, the root node will change from window to window.document, and the child nodes will change to reflect the child objects for the document node.  Additionally, the window portion of the root node can be clicked to return to the root window context.

Editing JavaScript Using Visual Studio .NET

Mark Wagner
Castle Rock Software, LLC

December 22, 2004

Summary: Use the Visual Studio .NET development environment as your JavaScript editor.

Technologies and Tools

  • JavaScript
  • Visual Studio .NET

As a .NET developer, I have become very comfortable with the Visual Studio .NET development environment.  As a result of my profession I spend most of my time working with this application.  I have recently increased my use of JavaScript and wanted an easy-to-use editor that wouldn’t take long for me to become productive using.  I have debugged JavaScript with .NET on and off for a while now, but never did I really need to work solely with JavaScript.  Usually, I am working within the context of an ASP.NET sever-side project.

The purpose of a scripting language such as JavaScript, is to provide a flexible, forgiving language to accomplish relatively simple code logic.  My primary intent was simply to use Visual Studio .NET as my JavaScript editor in order to take advantage of the built-in Intellisense and debugging it provides; and I am very comfortable with VS .NET and liked the idea of having a single development environment.  A significant portion of my testing and debugging will take place within the browser (Internet Explorer, Netscape, and others), but Visual Studio does have a few nice tools that can be used to debug such as the watch window.

Creating a new JavaScript ProjectI begin by creating a new “JavaScript” project by selecting the File > New > Project menu option.  I happen to use C# when I code, so I selected the C# Projects folder; however, you could just as easily select the Visual Basic Projects.  Once you have selected your folder, select the Empty Web Project icon and then specify the name of your project.  In the sample below my project name is MyJavaScriptProject.  This will create a simple web project with no files in it.

jsEditorSampleNewProject

Next, I add a new HTML page to my project.  Below is a sample of my simple completed HTML page.  When you add your HTML page, it will be empty compared to my example below.  As you inspect the HTML code below you will find it is a very simple HTML page with mostly javascript code contained within script tags.  Keep in mind, you can edit javascript (.js files) files as well.  However, since javascript files do not have a context by themselves, you will not get the full Intellisense available.  This is because the JavaScript code in the .js files is not within the context of an HTML document.  For example, you will not get the document object within your Intellisense.  Although you can still code using the document object, I like having the Intellisense available.  At least for now.

jsEditorSampleHTML

Quick NoteMake sure you allow (enable/disable) the JavaScript debugging in your Internet Explorer options.  These are usually in the Advanced section.  This will allow any JavaScript errors that occur while you test in your Internet Explorer browser to attach to your Visual Studio .NET debugging environment.

IntellisenseThe Visual Studio .NET HTML editor will provide Intellisense.  The use of Intellisense plays a major factor in my productivity.  Without it, I find myself digging through online help and books much more than I would like.  Even better, Visual Studio .NET provides Intellisense for the browser you want.  You do this by setting the targetSchema property of the HTML document in the properties dialog.  Below you can see the available schemas to chose from.  I find myself switching between Internet Explorer 5.0 and Netscape Navigator 4.0 options.  This allows me to easily use Intellisense when creating browser specific javascript code. 

Changing this targetSchema property tells the Visual Studio .NET editor what browser I would like my Intellisense to be compatible with.  When testing javascript code specific to Netscape I select the Netscape Navigator 4.0 option.  Then for example, when I type the javascript keyword/object document followed by the usual dot (period), I get the Intellisense populated with all the Netscape Navigator 4.0 compliant properties and methods.  The same is true when I select the Internet Explorer 5.0 option.

An important point to remember is that JavaScript is not strongly typed.  Because of this, the Visual Studio .NET editor cannot provide Intellisense for your JavaScript variables and functions.  However, your declared var-iables will appear, which is kinda nice.  I am not familiar with any of the other more popular JavaScript editors.  I expect they may try to perform some sort of design-time variable typing via reflection.  That would be purely a guess on the editors part, yet while keeping this point in mind, any help an editor provides is of benefit to the developer.

  jsEditorSampleTargetSchema

Testing My JavaScriptI can test my “JavaScript” project using the Start Without Debugging menu option, or Ctrl+F5.  This may be more of a convenience than a necessity.  Alternatively, I could simply open my test browser (IE, NS, Firefox, etc.) and point the url to my local project.  I typically just press the Ctrl+F5 keys.  Also, don’t forget to set the default page for your project to your HTML page first.

jsEditorSampleStartWithouDebugMenu

Conclusion

My appreciation for JavaScript continues to grow.  This is especially true as the standardization and functionality continues to improve between Internet Explorer, Netscape Navigator, and now Firefox.  I will admit that Visual Studio .NET is probably not the best JavaScript editor available.  However, it is much better than using a simple text editor, which is often done.  I have not taken the time to look into editors and debuggers for JavaScript.  I expect they provide more for the JavaScript developer since that is what they are specifically designed for.  I have personally not felt the need to dedicate time in learning the “best of’s” for each JavaScript editor available.  However, I would appreciate recommendations or suggestions you may have.

Book: JavaScript, The Definitive Guide

JavaScript, The Definitive Guide

Book-JavaScript I have been reading the book JavaScript, The Definitive Guide by David Flanagan.  With the increasing amount of valuable and clear content available on Internet, I have found myself buying fewer books over the last three years or so.  I often find most books are only sprinkled with any real information and bloated will filler content just to sell the book.  This is certainly not the case for this JavaScript book.  Rarely can I sit down and read a technical book from cover to cover, but this book is certainly an exception, and exceptional!  I highly recommend it.  Every page has been worth my time.

Building a Better Busy Box – Ver 1.2

Building a Better Busy Box – Ver 1.2 (Processing… Please Wait)
 
Mark Wagner
Castle Rock Software, LLC

Updates

  • February 16, 2005 – Rewrite to use an IFRAME instead of a DIV tag.
  • January 7, 2005 – Fixed z-Index attribute.
  • November 13, 2004 – Original article

Summary: We often need to provide a user message informing the user that their request is “processing”.  Like the hour-glass mouse pointer lets the Windows user know the system is busy processing their last request, I have a simple, clean, and effect solution to providing this on web pages.

BusyBox Demo

Download Files

Technologies employed

  • JavaScript
  • HTML (ASP.NET)

Supported browsers 

  • Internet Explorer 6
  • Netscape Navigator 7.1, 7.2
  • Firefox 1.0
  • No other browsers have been tested

Introduction
Anyone who has used the Internet for more than a few hours has encountered times when the “Internet” is being slow.  I use the term “Internet” in jest here since it is often the term used when websites are not responding as quickly as we would like.  As most of us know, the problem is more often caused by an over-worked website, one that is unable to handle its current workload.  This article does not address any performance issues as that is a much larger topic for another time.  However, for those well designed and well cared-for websites there are very acceptable times when displaying a “processing” message to the user is very helpful and very appropriate.

I have certainly experienced times; as I am sure you have, where after clicking a submit or search button I began to wonder if the web server was going to process my request successfully.  Why shouldn’t it.  I didn’t expect it to take more than a second or two.  Performing functions like a search, report generation, or the processing of a large order, can often take more time than we would like.  These predictably slow responding places in an application are ideal candidates for user feedback in the form of a processing message.  As long as your website is not normally slow, your users will appreciate being notified of potentially long running processes.

There are a number of different approaches to accomplishing this.  One of the more common methods is to navigate to an intermediate page where an animated image and/or message are presented to the user.  The intermediate page then immediately initiates the process of navigating to the long-processing page.  This allows the intermediate “please wait” page to be displayed to the user while the long-processing target page is crunching away.  When the target page completes its long process it then begins rendering to the user’s browser, thus replacing the “please wait” message.  While this technique works well when navigating from page A to page B, it does not work well when a post-back (from page A to page A) is needed.  Additionally, having the benefits of things like ViewState become discarded.

My Approach
The approach I am about to cover functions just as well during a post-back as it does when navigating from page X to page Y.  Moreover, there is no need (or desire) to have an intermediate processing page.  If you are using a custom base page for your application; (i.e. a MasterPage), it becomes even easier to user.  I have added this to my personal CastlePage class making it very easy to use at anytime.

My approach is to pre-load my busy box message in a hidden IFRAME  tag on any page that will navigate (or post-back) to a potentially long running process. After all, my busy box message has a pretty small code footprint. The page will begin it’s unload process whenever the browser posts to a new page or performs a post-back. By placing JavaScript code in the onbeforeunload event of the body tag I can instantly reveal the busy box message to the user. Since this is part of the original page it will display immediately and remain visible until the new page completes its processing and begins to render in the user’s browser. Best of all, this works great with post-backs too.

My approach is:

  • Render the busy box message in a hidden IFRAME tag wherever we have a page that may post to a long processing page.
  • Display the busy box message before leaving this page (or posting back to the same page) by using the onbeforeunload event on the html body tag.  Note: An alternative method for browsers that do not support the onbeforeunload event is also discussed later.
  • Use JavaScript to perform a simple animation to the client.

Continuing to Learn
My first pass at this was to use an animated GIF image to fulfill my animated desires.  Putting together a quick prototype didn’t take long, but I immediately realized, remembered, discovered (pick one that best flatters me) that the .gif images stop animating once a post-back or navigation to another page is initiated.  This is consistent for all my test browsers (IE, NS, Firefox).  Although this realization didn’t bring my approach to a crashing halt, the thought of having only a static image was less than exciting.  Fortunately, I noticed that my image buttons still alternated to the hover image when I moved the mouse over them.  That’s when I realized that although GIF image may stop animating; JavaScript is still working hard – in all my test browsers.  With this said, I decided to animate the images using JavaScript.  This added a little more work, but as you will see, not much more work.

JavaScript Animation
First and foremost, I used my new copy of JavaScript – The Definitive Guide by David Flanagan as my sole JavaScript resource.  This now famous “Rhino” book continues to be well received by developers.  I have to agree as I found this book to be very well written and packed with excellent information.

An animated .GIF image is nothing more than a series of images that are displayed in rapid succession.  Since the web browsers won’t do this for me, I will do it myself using JavaScript.

My animation will require a number of images that will be displayed in rapid succession.  To allow the animated image to be developer-defined (customizable), I will need to know the number of images and the image names.  To help manage this animation and to keep it clean, the image names must have a predicable sequence number in a predictable position.  To accomplish this I have two image name requirements.

  • The names may be anything the developer wants as long as the image name prefix and suffix are consistent for every image.
  • The first image sequence number will be zero.

Here is the required image name format:

  • PrefixName + SequenceNumber + SuffixName

Here are valid image name examples:

  • BusyImage0.gif,  BusyImage1.gif,  BusyImage2.gif,  BusyImage3.gif, …, BusyImage6.gif
  • Images/BusyImage0.gif,  Images/BusyImage1.gif,  Images/BusyImage2.gif
  • Animate0Image.gif,  Animate1Image.gif,  Animate2Image.gif, …, Animate8Image.gif

The three image name properties used to define the images are ImageNamePrefix, ImageNameSuffix, and ImageCount; each of which are described below.

Before I dive into the details of my JavaScript, I thought it would be helpful to provide a quick overview of what my JavaScript BusyBox object interface will look like.  Here is a quick summary of the interface.

Constructor

BusyBox(id, varName, imageCount, imageNamePrefix, imageNameSuffix, imageDelay, width, height, url)

The parameters provided in this constructor are described in the properties section.

Properties

id

  • Defines the id of the IFrame tag to use with this instance of the BusyBox object.

VarName

  • This string value defines the name of the JavaScript variable containing the instance of this BusyBox object on the client’s machine.  This is needed so that we can use the setTimeout() statement, discussed later.

ImageCount

  • This integer value defines the number of images to use in the animation.

ImageNamePrefix

  • This string value defines the name prefix of the images that are used in the animation.
  • Example: “myBusyBoxImage_” or “images/myBusyBoxImage_”.

ImageNameSuffix

  • This string value defines the extension of the images that are used in the animation.
  • Example: “.gif” or “.jpg” or “_ani.gif”.

ImageDelay

  • This integer value defines the length of time in milliseconds to display each image.

Width

  • This defines the width (in pixels) of the busy box IFRAME tag.
  • Netscape and Firefix require this value to be defined.  For Internet Explorer users, the width is automatically calculated using the BusyBoxDiv tag attributes.

Height

  • This defines the height (in pixels) of the busy box IFRAME tag.
  • Netscape and Firefix require this value to be defined.  For Internet Explorer users, the width is automatically calculated using the BusyBoxDiv tag attributes.

BusyBoxUrl

  • Optional
  • Defines the url to the page containing the custom busy box layout.
  • If this value is omitted or null during the instantiation call, the internally defined layout is used.  The RenderContent() method is used to render the internal default layout.

Images

  • This array contains a reference to every image in the animation.  This property is populated during the constructor via the CacheImages() method.
  • This property should be treated as read-only.

CurrentImageIndex

  • This value is automatically calculated and incremented during the animation process.
  • This value should be treated as read-only.

Enabled

  • Get or set this Boolean value to enable or disable (a false value) the BusyBox using JavaScript.
  • This allows client-side JavaScript to conditionally enable or disable the BusyBox, should that become necessary.  A false value will prevent the busy box from being displayed when the Show method is called.
  • The default value is true.

IsAnimating

  • Returns a boolean value representing the state of the animation.
  • This should be treated as read-only.

IsVisible

  • Returns a boolean value representing the visibility state for the busy box.
  • This should be treated as read-only.

Methods

Show()

  • Displays the busy box by changing its visibility from hidden to visible.
  • Centers the busy box over the current window scroll position.
  • The BusyBox message will be displayed only if the Enabled property is true.  If the Enabled property is false, this Show method will do nothing.

Hide()

  • Hides the busy box by changing its visibility to hidden.
  • Provides a method to hide the BusyBox using JavaScript should it be necessary.  This may be called anytime using client-side JavaScript.
  • Note: This was fixed from the previous version.

Animate()

  • Performs the animation process.
  • This method should be treated as private.  There is no need to call this method directly.  The StartAnimate method should be called to start the animation process.

StartAnimation()

  • Starts the animation process.
  • Provides a method to start the animation process using JavaScript should it be necessary.  This may be called anytime using client-side JavaScript.

StopAnimate()

  • Stops the animation process.
  • Provides a method to stop the animation using JavaScript should it be necessary.  This may be called anytime using client-side JavaScript.

CacheImages()

  • Pre-loads the images from the server to improve the animation performance.  There is no need to directly call this method since it is called by the constructor.
  • This should be treated as private.  There should be no need to call this method.

GetIFrameDocument()

  • Returns a reference to the document object in the IFrame using the appropriate method depending on the browser version.
  • This should be treated as private.  There should be no need to call this method.

LoadUrl()

  • Changing the src attribute for an IFrame tag causes each new page to be added to the browsers history object. This causes undesired results for the user when they click the back button. Instead, we can use the document.location.replace() method to correctly load our busy box page into our IFrame.
  • Arguments: url – url to the busy box page. BusyBox.prototype.LoadUrl = function(url)
  • This should be treated as private.  There should be no need to call this method.

RenderContent()

  • This method is used when the default busy box layout is used; not a custom layout. This method is called when the url argument for the constructor is null.
  • This should be treated as private.  There should be no need to call this method.

Resize()

  • Resizes the busy box IFrame by setting its width and height attributes to the size of its contents for Internet Explorer browers.  For Netscape and Firefox, the width and height defined in the constructor are used to resize the IFrame.
  • This should be treated as private.  There should be no need to call this method.
  • Help: If anyone knows how to reliably determine ths size of the contents for Netscape and Firefox, please let me know.  Thanks.

Center()

  • Centers the busy box IFrame on the page regardless of the browsers scroll position. This ensures the busy box is presented to the user in a visible location in the window.
  • This should be treated as private.  There should be no need to call this method.

JavaScript Code

The JavaScript needed to perform the animation is pretty simple. The JavaScript found in the BusyBox.js file is static and used as is by placing a reference to it via the standard script tag. There is only one line of custom JavaScript code needed for any page, and that is to create an instance of the BusyBox object. Here is a sample of that code where I have chosen to use the variable name of “busyBox”.

var busyBox = new BusyBox(“BusyBoxIFrame”, “busyBox”, 4, “images/gears_ani_”, “.gif”, 125, 147, 206)

You will find the above line of code shown again in the HTML code below. I will not cover each line of JavaScript code; however, there are a couple key items worth pointing out. The first is the BusyBox constructor. The constructor executes the CacheImages method so that all the images used in the animation will be “pre-loaded” and ready for immediate use. The process used to cache the images simply forces the browser to retrieve the images during the initial page load. The images are not actually stored in the Images array. Additionally, the Images array provides an easy reference to each image used in the animation.

The Animate method sets the current image to display and then calls the JavaScript function setTimeout(). The set setTimeout() function executes the next statement in x number of milliseconds. As you can see, setTimeout() continues to call itself to display the next sequential image until the page is unloaded or until the animation is stopped using the StopAnimate() method. This is 100% of the animation process. Again, pretty simple (and straight out of the Rhino book).

The Show method has only a few small tasks, which are 1) to determine the size of the developer-defined busy box (for IE browsers).  2) Position the busy box in the center of the users browser regardless of the scroll position.  3) To begin the animation process.

The following code can be found in the CastleBusyBox.js file.  Note: The actual CastleBusyBox.js file contains a brief summary of comments for each method, and has a few more helper methods.

1function BusyBox(id, varName, imageCount, imageNamePrefix, imageNameSuffix, imageDelay, width, height, url) 2{
3   // Initialize object
4   this.id = id; 5   this.ImageCount = imageCount; 6   this.CurrentImageIndex = 0; 7   this.ImageWidth = 0; 8   this.ImageHeight = 0; 9   this.ImageNamePrefix = imageNamePrefix; 10   this.ImageNameSuffix = imageNameSuffix; 11   this.ImageDelay = imageDelay; 12   this.DivID = "BusyBoxDiv";
13   this.ImgID = "BusyBoxImg";
14   this.Enabled = true;
15   this.Width = width;
16   this.Height = height;
17
18   // Retain the name of the instantiated object variable so that we can animate 
19   // using the setTimeout statement
20   this.VarName = varName; 21
22   // Allows us to stop the animation with clearTimeout(), should we ever want to
23   this.timeout_id = null;
24
25   // Cache (pre-load) images
26   this.CacheImages(); 27
28   // Url to the page containing the busy box.
29   this.BusyBoxUrl = url; 30
31   // Get reference to the IFrame object
32   this.IFrame = document.getElementById(this.id);
33
34   // Hide the busy box
35   this.Hide();
36
37   if( this.BusyBoxUrl ) 38      // Load the busy box contents using a custom layout page.
39      this.LoadUrl(this.BusyBoxUrl); 40   else
41      // Load the busy box contents using the internally defined layout.
42      this.RenderContent(); 43
44   // If this browser does not support IFRAME tags then disable this control. The
45   // next version will implement the use of a DIV instead of the IFRAME tag; 
46   // even though there are a couple minor issues with using DIV tags.
47   if( !frames[this.id] )
48      this.Enabled = false;
49}
50
51BusyBox.prototype.GetIFrameDocument = function() 52{
53  var doc; 54
55   if( this.IFrame.contentDocument ) 56      // For NS6
57  doc = this.IFrame.contentDocument;
58   else if( this.IFrame.contentWindow )
59      // For IE5.5 and IE6
60      doc = this.IFrame.contentWindow.document;
61   else if( this.IFrame.document )
62      // For IE5
63      doc = this.IFrame.document;
64   else
65// TODO: Confirm this should be the default
66      doc = this.IFrame.document;
67
68   return doc;
69}
70
71BusyBox.prototype.LoadUrl = function(url) 72{
73   // Get a reference to the document object in the IFrame
74  var IFrameDoc = this.GetIFrameDocument(); 75
76   // Load the url using the replace method. This will prevent the browsers 
77   // history object from being updated with the new busybox url; thus allowing 
78   // the back button to function as desired for the user.
79  IFrameDoc.location.replace(url); 80}
81
82BusyBox.prototype.RenderContent = function()
83{
84   // Get the IFrame document object
85   var doc = this.GetIFrameDocument();
86
87   var wh = "width:" + this.Width + "; height:" + this.Height;
88   var style = " style='BORDER: navy 3px solid; POSITION: absolute; " + wh + "'";
89
90   doc.open();
91   doc.writeln("0px; Background-Color: white" _mce_style="margin: 0px; background-color: white;">");
92   doc.writeln("   <div id='" + this.DivID + "' align=center " + style + ">");
93   doc.writeln(" <img id='" + this.ImgID + "' src=''>");
94   doc.writeln("      <br><h3>Processing</h3>");
95   doc.writeln("   </div>");
96   doc.writeln("</body>");
97   doc.close();
98}
99
100BusyBox.prototype.Resize = function()
101{
102   // Resize the busy box IFrame.
103   if( BusyBox.IsBrowserIE() )
104   {
105      // Set the width by looking at its contents
106      var div = frames[this.id].document.getElementById(this.DivID); 107      this.IFrame.style.width = div.offsetWidth;
108      this.IFrame.style.height = div.offsetHeight;
109   }
110   else
111   {
112      // Set the width to the value specified.
113      this.IFrame.style.width = this.Width;
114      this.IFrame.style.height = this.Height;
115   }
116}
117
118BusyBox.prototype.Center = function()
119{
120   if( !this.IFrame )
121      return;
122
123   // Center the BusyBox in the window regardless of the scroll positions
124  var objLeft = (document.body.clientWidth - this.IFrame.offsetWidth) / 2;
125  var objTop = (document.body.clientHeight - this.IFrame.offsetHeight) / 2;
126  objLeft = objLeft + document.body.scrollLeft; 127  objTop = objTop + document.body.scrollTop; 128
129   // Position object
130   this.IFrame.style.position = "absolute";
131   this.IFrame.style.top = objTop;
132   this.IFrame.style.left = objLeft;
133}
134
135BusyBox.prototype.CacheImages = function()
136{
137   // Instantiate the array to store the image references
138   this.Images = new Array(this.ImageCount); 139
140   // Load all the images to cache into the aniframes array
141   for(var i = 0; i < this.ImageCount; i++) 142   {
143      this.Images[i] = new Image();
144      this.Images[i].src = this.ImageNamePrefix + i + this.ImageNameSuffix; 145   }
146}
147
148BusyBox.prototype.IsAnimating = function() 149{
150   if( this.timeout_id == null)
151      return false;
152   else
153      return true;
154}
155
156BusyBox.prototype.IsVisible = function() 157{
158  var ifrm = document.getElementById(this.id);
159
160   if( ifrm.style.visibility == "visible" && ifrm.style.width > 0 )
161      return true;
162   else
163      return false;
164}
165
166BusyBox.prototype.Animate = function()
167{
168   // Assign the current image sequence to display
169   if( frames[this.id] )
170      // browser supports frames
171      frames[this.id].document.getElementById(this.ImgID).src = this.Images[this.CurrentImageIndex].src; 172   else
173      // browser does not support frames
174      document.getElementById(this.ImgID).src = this.Images[this.CurrentImageIndex].src; 175
176   // Auto re-center and re-size the busy box.  This will force the busy box to 
177   // always appear in the center of the window even if the user scrolls.
178   this.Resize();
179   this.Center();
180
181   // Increment the current image index
182   this.CurrentImageIndex = (this.CurrentImageIndex + 1)%this.ImageCount; 183
184   // Display the next image in (imageDelay value) milliseconds (i.e. 125)
185   this.timeout_id = setTimeout(this.VarName + ".Animate();", this.ImageDelay); 186}
187
188BusyBox.prototype.StartAnimate = function() 189{
190   if( this.IsAnimating() ) 191      return;
192
193   this.Animate();
194}
195
196BusyBox.prototype.StopAnimate = function() 197{
198  clearTimeout(this.timeout_id);
199   this.timeout_id = null;
200}
201
202BusyBox.prototype.Hide = function()
203{
204   this.StopAnimate();
205
206   // Hide the busy box.
207   this.IFrame.style.visibility = "hidden";
208   this.IFrame.style.width = 0;
209   this.IFrame.style.height = 0;
210}
211
212BusyBox.prototype.Show = function()
213{
214   if( !this.Enabled )
215      return;
216
217   if( this.IsAnimating() || this.IsVisible() )
218      return;
219
220   this.Resize();
221   this.Center();
222
223   // Set the busy box to be visible and make sure it is on top of all other controls. 
224   this.IFrame.style.visibility = "visible";
225   this.IFrame.style.zIndex = "999999";
226
227   // Start the animation
228   this.StartAnimate();
229
 

The .ASPX (HTML) Code

The required code in the .aspx or html page is quite small and consists of four pieces of code.

The first html piece is the onbeforeunload event on the body tag.  This event is fired just before a page is unloaded.  This includes post-back and hyperlinks to other pages.  In the onbeforeunload event we place the JavaScript to display the Busy Box to the user prior to any action that results in leaving this page or reloading it.

Discuss how to use a SPAN tag around buttons or links instead of the onbeforeunload event of the body tag.

The second html piece is simply the reference to the JavaScript class defining the BusyBox class, which is used to display and animate the busy box.

The third html piece instantiates my BusyBox object and assigns it to my working variable named busyBox.  My sample uses four images and each image is displayed for 125 milliseconds with a width of 147 and height of 206.

Example:

var busyBox = new BusyBox(“BusyBoxIFrame”, “busyBox”, 4, “images/gears_ani_”, “.gif”, 125, 147, 206)

The fourth html piece is my Busy Box iframe tag.  The iframe is used to contain the BusyBox layout.  The BusyBox layout is nothing more than a div tag containing an img tag.  The size, color, and content of this busy box are completely up to you.  This allows you to create a busy box that is as generic or personalized as your site needs.  There are two important components in a busy box, the  div tag and the embedded img tag.  These two tags must contain the same id’s defined in the BusyBox JavaScript object properties DivID and ImgID.  The default values for these two properties are “BusyBoxDiv” for DivID, and “BusyBoxImg” for the ImgID property.  Assigning your html  div and img tags with these id values is the easiest.  However, you may assign any id you wish; however, you will need to assign your custom values to the busybox.DivID and busybox.ImgID properties immediately after the instantiation of your busybox JavaScript object.

Sample .ASPX (HTML)

<body onbeforeunload="busyBox.Show();">
   <script language="javascript" type="text/javascript" src="CastleBusyBox.js"></script>       <form>
         <P>    [Your Page Specific Content Here]    <iframe id="BusyBox1" name="BusyBox1" frameBorder="0" scrolling="no"ondrop="return false;"></iframe></P>
         <P>
	<INPUT id="Submit1" type="submit" value="Submit" name="Submit1"></P>
      <script language="javascript" type="text/javascript">          // Instantiate BusyBox object          var busyBox =    new BusyBox("BusyBox1", "busyBox", 4, "images/gears_ani_", ".gif", 125, 147, 207);       </script>
   </form>
</body>
 

Alternatives to Using the OnBeforeUnload Event

The onbeforeunload is supported by Internet Explorer 6, Netscape 7.2 (not 7.1), and Firefox 1.0.  The onbeforeunload event may not be the best solution for your particular needs.  Another solution is to place the busybox.Show() method in the onclick event of the html elements (button, link etc.) that need to cause the busy box to appear.  If the particular html tag does not have an onclick event, you can wrap your control in a span tag and use the onclick event of the span tag.  I use this all the time.

Example:

<span onclick="busyBox.Show();">
	<a href="anypage.htm">Any Page</a>
</span>

This allows you to specifically control which buttons and/or links cause the busy box to appear.

Another issue surfaced by users of the pervious version was the busy box appearing and remaining on the screen when a popup window was launched.  This assumes your are using the onbeforeunload event, and you want to prevent the busy box from appearing.  You can prevent this from happening by placing a “return false;” after the popup statement in your javascript event code.

Example:

<A onclick="window.open('anypage.htm'); return false;" href="#"> Open window</A>

Creating a BusyBox Web Control

I have created an ASP.NET web control to allow for easy use in ASP.NET pages.  You can find the control in my BusyBox Web Control article – to be posted shortly with a link insterted here.