Archive for June 2008

 
 

Managing Internet Explorer, JavaScript, and client and offset values returning zero

I’ve been working on building a custom modal control for someone else that will ideally be used in a variety of places throughout their site. Essentially, the control will allow a developer to create a dialog and style it how s/he would want it to appear, and then pass it to my code. My code will then process it, bundle it up with a semi-transparent background, and then overlay their dialog centered above all of the other elements on the page.

For the most part, it was going well - the control was performing the exact same way across all of the major browsers, and it was easy to plug existing code into it; however, while testing it on a variety of pages, I came across a bug that ended up plaguing me for much longer than it should have. There’s a function in the JavaScript that uses each element’s offsetWidth and offsetHeight values to center that element in the middle of browser window regardless of its size. Oddly enough, on one of the pages that I was testing, I was noticing that Internet Explorer was not properly centering the element. Upon further investigation, I noticed that the element’s offsetWidth, offsetHeight, clientWidth, and clientHeight values were all being returned as zero.

Naturally, I ended up googling around for a solution to the problem. I didn’t come up with much, but I did find this page on MSDN which ended up giving some insight - the page contained tables and they were the culprit for this behavior. Although this helped me pinpoint this problem, it didn’t help revealing a solution. Additionally, Firefox, Safari, and Opera all displayed it correctly regardless of if tables were present on the page or not. So, I resolved to spending some time understanding how tables caused this problem in hopes of coming up with a way to manage it. Ultimately, I came up with a solution and thought I’d share it here. Before diving into code, I thought I’d explain how it works.

About document.readyState

Internet Explorer implements a property on the document object called readyState. Technically, it’s present for the sake of the XmlHttp object, but it can used to determine the state of the current document (which is useful, as you’ll read shortly). There are five different ready states:

  1. Uninitialized
  2. Loading
  3. Loaded
  4. Interactive
  5. Complete

The important thing to take away from this is that IE will not have the offsetWidth/offsetHeight/clientWidth/clientHeight values calculated until state five, but the JavaScript function was processing the element in step four.

Capitalizing on document.readyState with IE

My fix capitalizes on document.readyState. Because Firefox, Safari, and Opera all returned ‘undefined’ for this property, it meant I didn’t have to re-write a lot of the existing functionality - I just needed to incorporate a single case for managing IE’s behaviors. Assume that this.bIsE is a flag set earlier in the code determining whether or not I’m using IE. Also assume that _InitializeComponents() contains logic responsible for getting some of the page’s elements ready. Here’s what I did:

if(this.bIsIE && document.readyState != ‘complete’) {

var self = this;
self.onLoadHandler = window.setInterval(function() {

if(document.readyState == ‘complete’) {

self._InitializeComponents();
window.clearInterval(self.onLoadHandler);

}

}, 100);
} else {

self._InitializeComponents();

}

Basically, the way this works is that is that if it’s not IE, initialize the components and proceed; otherwise, if IE is the current browser and it’s not in the ready state, then fire the readyState check every 100ms. If the document eventually reaches the ready state, then initialize the components and stop the interval function. Overall, it’s not perfect, but it works and it accomplished what I needed.

Organizing Knowledge Generated in Software Development

For anyone that’s ever been responsible for working a website or software application that someone else has created, or for anyone that frequently works on developing a large piece of software, you’re likely to touch various pieces of code in that application. We’ve all got our own style of writing code, but given any major piece of software, there are going to be standard ways for creating certain types of objects.

For example, given any distributed web application, there is likely to be several ways to get information from the front end to the back end and have it replicated across all of the databases. For any desktop application, there are ways to correctly generate objects at runtime that will do exactly what you need them to do as opposed to creating giant objects are design time to cover every major scenario for your situation.

Obviously, and as with most things in programming, there are n-different ways to accomplish any given task; however, I firmly believe that well-designed software and good software engineering practices setup standard ways (or even frameworks) that are conducive to providing a correct way of accomplishing a task versus a way that works.

Ultimately, the longer you spend working on any large piece of software, the more likely you are to touch a wide breadth of areas in the code base. Additionally, you’re likely to hit varying degrees of depth in that code, as well. For every step across the code that you take and for every level deep in the code that you go, you may find yourself in a situation where you need to create a new object or refactor some existing code. Assuming that there is a standard way for creating to objects, integrating new features, or whatever else you may be doing, you’re going to be gaining experience with this area of the code. With that experience, you’re likely to be expected to be able to do something similar in the future.

What happens, though, in three months down the line when you’re neck deep in front-end development and you’ve just been asked to dive down into the application layer to develop some new code that will be responsible for translating information passed down from the front end and process it in some way before sending it over to the back end system? For some, no big deal - they’re gifted in that way. For others, they are likely to copy/paste from some similar code, patch it up, and release it. Copy/Paste is a terrible idea and, in my opinion, should never be done in almost any situation. Others may refer to some old notebook that they keep filed away from previous projects. Whatever works best for you is what you should do (except for Copy/Paste!).

Personally, I’ve been running a wiki on my local development box in which I keep all notes relative to nuances for various languages, framework notes, development techniques, and general reference notes that I come up with while working on aspect of a project. I’m a fan of doing this not only because it’s really easy to keep a web browser open on one monitor keeping notes based on code that’s open in an IDE on another monitor, but because it’s easier to organize than a notebook. Using links and a search engine beats bookmarks and skimming pages for me any day.

I like doing this because it prevents my file cabinet from getting too filled with stacks of notebooks, but it also rids me of the uncertainty of Is this the right way to do this? I can’t remember away and replaces it with Is this is the right way to do this? Let me check what I’ve done before. Generating knowledge in any given situation is always great, but it’s only as good as your ability to reuse it in the future. Keeping that information organized and easily accessible helps.

Just in case you’re wondering, I’ve been using Instiki and it has served me well. I’m not saying it’s the best or anything, but if you’re looking for something that is easy to setup and with which it is easier to interact, then I recommend it. Do you keep notes on various projects that you work on? What utilities do you use to help out with that?

Automated Backups with Windows and Ubuntu, Part 2

Getting SyncToy to synchronize its paired folders with Ubuntu is a relatively easy process, but it requires some initial setup. Basically, SyncToy will utilize a network drive that is mapped to your Ubuntu machine. Luckily, Samba makes this really easy.

Setup The Ubuntu Machine

Setting Up Samba

The most recent version of Ubuntu ships with Samba already installed, so you can skip down to the configuration section if you’re already running Ubuntu 8.04. If not, launch a terminal - there are a couple of packages that must be installed.

sudo apt-get install samba smbfs

This is all that’s required to install Samba on the machine. Before you can begin sharing directories with other Windows machines, some initial Samba configuration is required. First, open the Samba configuration file with whatever text-editor you favor the most.

sudo gedit /etc/samba/smb.conf

Once the editor opens, find the area of the file that manages security and authentication. Uncomment the line that sets security equal to user. Also setup a map for usernames. The revised version of the configuration file should look like this:

####### Authentication #######
# “security = user” is always a good idea.
# This will require a Unix account
# in this server for every user accessing the server. See
# /usr/share/doc/samba-doc/htmldocs/Samba-HOWTO-Collection/
# ServerType.html
# in the samba-doc package for details.
security = user
username map = /etc/samba/smbusers

The last piece of Samba configuration is to setup a username and password. First, in the terminal, setup the password with this command:

sudo smbpasswd -a <username>

I recommend using your Ubuntu username, but you can technically use whatever you want. Lastly, setup the smbusers file that we specified in the mapping in the Samba configuration file. To do this, open the smbusers file with this command:

sudo gedit /etc/samba/smbusers

In this file, map the username of user you are currently logged in as to the username specified when setting the password above. The line should look like this:

<username> = “<username>”

This finishes setting up Samba; however, before mapping the drive from Windows, a directory must be shared from the Ubuntu machine.

Sharing Directories in Ubuntu

This step is extremely easy. For the purposes of this post, I’m assuming that the directory to be mapped to the Windows machine is located in your home directory.

So, launch your favorite file manager and navigate to your home directory. If you’re planning to create a new directory for backup, then do that now. Right-click on the directory that you wish to share and select “Sharing Options.” In the window that appears, perform the following actions:

  1. Check the option to Share this folder
  2. Specify the share name. Usually, this is the same name as the directory.
  3. Check the option to Allow other people to write in this folder.
  4. Click Modify Share. If you receive a net 255 error, then you’re attempting to share a directory with a name that matches an existing username on the system and you’ll need to choose another name.

Once this is done, the Samba/Ubuntu configuration should be complete.

A quick note: Some people seem to experience host name problems when they’ve setup Samba on their existing Ubuntu installation. To rectify this problem, edit the hosts file in your favorite text editor by entering this command:

sudo gedit /etc/hosts

In that file, verify that the first two lines read like this:

127.0.0.1 localhost <your-machine-name>
127.0.1.1 <your-machine-name>

Configuring Windows

Mapping Ubuntu’s Directory to Windows

From your desktop, double-click on My Computer. When the Explorer window appears, do the following:

  1. Click on the Tools menu and select Map Network Drive….
  2. In the next window, select the drive letter that you wish to refer to your Ubuntu shared drive
  3. In the folder field, enter the name of the machine and the shared directory in this format \\your-machine-name\shared-directory-name
  4. Specify whether or not you want Windows to automatically connect to the Ubuntu machine at logon.
  5. Click Finish

Permitting everything has been setup correctly, you should a new drive should appear in Windows Explorer that maps to the shared directory in Ubuntu.

Setup SyncToy To Backup to Ubuntu

Configuring SyncToy is easy - now that there is a drive mapping from Windows to Ubuntu, it can be treated like any other Windows directory.

  1. Open SyncToy and click on Create New Folder Pair.
  2. For the left folder, select the directory on your Windows machine that contains the files you wish to backup.
  3. For the left folder, select the recently mapped drive.
  4. Select the synchronization configuration option as mentioned in Part 1.
  5. Name the folder pair.

If you wish to schedule asynchronous backups, then setup a second scheduled task using the process that was outlined in Part 1; otherwise, you’re all done.