Recently I wanted to make a web page design extend to the bottom of the browser even if there wasn't enough content to stretch the containing element to the height of the window.
If only the HTML or CSS spec had some kind of "remainder" value for widths and heights. There was the "*" width for the width attribute of Table Cells. But we don't have anything like that any other elements. Yeah, there is "auto" on width and height but that doesn't mean "fill the remainder" unless you are working in tables. But a table has to fill the remainder so it doesn't really count.
So the solution for my specific design, and hopefully it will be helpful to you, is to wrap the page with an element (I used DIV) and then give it a height of 100%. I then used a repeating background to fill down the element to the bottom of the window.
In order to make this work properly you also need to set the HTML, BODY, and FORM element HEIGHT values to 100%. This causes these elements to always stretch to the height of the window.
You can't specify a percentage height on an element unless its parent has a height specified as well. Also, you have to be careful with margins, padding, and borders on any element that you give a 100% height. If you're having trouble with always have scroll bars even when the page is only part full then you'd gain a lot be reviewing the Box Model. Read the W3C specs.
Thursday, October 26, 2006
Tuesday, October 24, 2006
IE7 released
IE7 has finally been released! So I'm a bit late. Personally, I'm happy for a new IE, but, professionally, it's just going to be a pain. Since you can't have side-by-side IE versions (not easily anyhow, but other browsers are the same way) it is difficult to build and test websites for IE6 and IE7.
I did install one of the IE7 betas in a virtual machine to test the web applications I have built and support. None of them had any issues which was encouraging.
I am a little surprised at the significant GUI changes Microsoft has decided to make for IE and the Office Suite. But I suppose it's not all that different than introducing the "Start Bar" in Windows 95/NT but change is hard.
I'm not a user interface expert but I believe that a consistent location is more important than "good" design. This is why Microsoft has a standard for Menus and Toolbars. You'll notice that the File, Edit and Help menus are almost identical in every program. The order of toolbar buttons is almost the same in every program and they are almost always in the same place.
While playing with IE7 I found myself moving the cursor up toward the 'Tools' menu to make configuration changes but it's not where it used to be. This makes for a slightly jarring transition. We seem to understand the idea of consistency between applications and webpages. Overall, I think these GUI changes are improvements and will make the browser's features easier to access. Hopefully these changes are leading toward making it so application functionality can more easily be discovered.
For example, I suck at MS Word. I can write a letter, change the font size, make it bold and so on. I can't make a table of contents that will auto-update the page numbers to match my chapters. I know it can be done because I've seen it. I've looked through the menus and some help but couldn't figure it out. The GUI does not lend itself to discovering this functionality. So I have the common Table of Contents that I have to constantly update, doesn't quite line up, and has the funny ........ with some converted to (...).
I did install one of the IE7 betas in a virtual machine to test the web applications I have built and support. None of them had any issues which was encouraging.
I am a little surprised at the significant GUI changes Microsoft has decided to make for IE and the Office Suite. But I suppose it's not all that different than introducing the "Start Bar" in Windows 95/NT but change is hard.
I'm not a user interface expert but I believe that a consistent location is more important than "good" design. This is why Microsoft has a standard for Menus and Toolbars. You'll notice that the File, Edit and Help menus are almost identical in every program. The order of toolbar buttons is almost the same in every program and they are almost always in the same place.
While playing with IE7 I found myself moving the cursor up toward the 'Tools' menu to make configuration changes but it's not where it used to be. This makes for a slightly jarring transition. We seem to understand the idea of consistency between applications and webpages. Overall, I think these GUI changes are improvements and will make the browser's features easier to access. Hopefully these changes are leading toward making it so application functionality can more easily be discovered.
For example, I suck at MS Word. I can write a letter, change the font size, make it bold and so on. I can't make a table of contents that will auto-update the page numbers to match my chapters. I know it can be done because I've seen it. I've looked through the menus and some help but couldn't figure it out. The GUI does not lend itself to discovering this functionality. So I have the common Table of Contents that I have to constantly update, doesn't quite line up, and has the funny ........ with some converted to (...).
Firefox 2.0
Firefox 2 has been released. I've been waiting until the official release before installing it on my system. I don't like to install software that is progressing towards release. It's not that I mind installing Beta software. It's just that when Firefox is moving towards an "Official" release they tend to put out several betas and RCs. I've gotten tired of making several installs and updates. I did install RC2 in a Virtual Machine that I was using to test IE7 (It's okay, they got along alright).
So far I like Firefox 2 pretty well. I decided to go for a "clean" install. I backed up my bookmarks, un-installed my existing FF installation and deleted my Profile files.
After the install I quickly re-installed my basic extensions. These include Gmail Manager, NoScript, IE Tab, Restart Firefox, Nuke Anything Enhanced, Linkification, Adblock Plus, Adblock Filterset.G Updater, and Download Statusbar. My browser just isn't a browser until I've installed these. So until there comparable plug-ins I don't think I'll be able to switch back to IE as my primary browser.
Being a web developer I also installed Html Validator, FireBug, Tamper Data, and View Source Chart. I use FireBug regularly but the others are on the edge of being un-installed since I rarely use them. But it's nice to have them ready when the need arises.
I'm giving a couple new extensions a try this time around which are FoxyTunes, All-in-One Sidebar, and MeasureIt. FoxyTunes is cool but I just got my Multimedia keyboard buttons working and it's much easier to use that. MeasureIt is very interesting and I think I may use it when first laying out my sites, but it seems like it should be merged with another extension web development extension (its the same for the Color Picker extension). I'll probably end up removing it after not using it for several months (just like Color Picker).
The All-in-One sidebar is great. It is a little weird and kind of hijacks the Addons, Download, and a few other windows. I think I've finally got it configured about right for my use. It does 2 things that I really like. It adds a vertical toolbar strip for bookmarks, history, downloads, etc. (which is customizable like the other FF toolbars) and it provides Toolbar buttons for the Error Console and the DOM explorer. I may never have to use the Tools menu again! Too bad many of the configuration changes require a browser restart (but I have an extension for that!).
The built-in spell checker is already working great. It even checks the spelling in the Compose window for this post. I've read that it only automatically checks the spelling in Textarea fields. I can understand the reasoning behind this design but I wish there was an option to have it check all text fields. I can't even find a setting in about:config. I'll just have to wait for an extension.
I installed a "CTRL-Tab" tab viewing extension. It's idea was original (something different than all the Expose clones) but didn't work correctly on my dual monitors. I usually have FF on the second screen and that's where it didn't work. I removed it but it seems to have left my CTRL-Tab shortcut hijacked and I can't switch tabs.
I tried a couple of the "Popular" themes from addons.mozilla.org but they didn't really compare to Firefox's default theme which is excellent.
The only changes left that I wanted to make were to the Tab clicking options. The tabs now include a close X on each tab. I have mixed feelings about this. I've used Xs on tabs before I tend to accidentally close the tab that I am trying to switch to. This usually happens only when there are many tabs and the tabs are small. Also, I use the middle-click and double-click shortcuts to open and close tabs so an X just kind of takes up space.
I tried a tab options extension (I can't remember its name) which allowed me to remove all the Xs on tabs or just the Xs on background tabs but it didn't let me modify the tab clicking options. I am now using "Tab Clicking Options" instead. This doesn't let me get rid of Xs but it does let me set what middle and double click does to tabs. I don't understand why the default settings are double-click to close tabs and middle-click to open tabs.
I found that in about:config you can change a settings and remove the Xs on background tabs without an extension. There is also an option for disabling background close but it doesn't seem to prevent you from clicking the X on background tabs so I'm not sure what this setting is for.
I'm going to give the Xs a chance since I've heard that once you get used to them you like them. But I think middle-clicking will be hard to beat.
So far I like Firefox 2 pretty well. I decided to go for a "clean" install. I backed up my bookmarks, un-installed my existing FF installation and deleted my Profile files.
After the install I quickly re-installed my basic extensions. These include Gmail Manager, NoScript, IE Tab, Restart Firefox, Nuke Anything Enhanced, Linkification, Adblock Plus, Adblock Filterset.G Updater, and Download Statusbar. My browser just isn't a browser until I've installed these. So until there comparable plug-ins I don't think I'll be able to switch back to IE as my primary browser.
Being a web developer I also installed Html Validator, FireBug, Tamper Data, and View Source Chart. I use FireBug regularly but the others are on the edge of being un-installed since I rarely use them. But it's nice to have them ready when the need arises.
I'm giving a couple new extensions a try this time around which are FoxyTunes, All-in-One Sidebar, and MeasureIt. FoxyTunes is cool but I just got my Multimedia keyboard buttons working and it's much easier to use that. MeasureIt is very interesting and I think I may use it when first laying out my sites, but it seems like it should be merged with another extension web development extension (its the same for the Color Picker extension). I'll probably end up removing it after not using it for several months (just like Color Picker).
The All-in-One sidebar is great. It is a little weird and kind of hijacks the Addons, Download, and a few other windows. I think I've finally got it configured about right for my use. It does 2 things that I really like. It adds a vertical toolbar strip for bookmarks, history, downloads, etc. (which is customizable like the other FF toolbars) and it provides Toolbar buttons for the Error Console and the DOM explorer. I may never have to use the Tools menu again! Too bad many of the configuration changes require a browser restart (but I have an extension for that!).
The built-in spell checker is already working great. It even checks the spelling in the Compose window for this post. I've read that it only automatically checks the spelling in Textarea fields. I can understand the reasoning behind this design but I wish there was an option to have it check all text fields. I can't even find a setting in about:config. I'll just have to wait for an extension.
I installed a "CTRL-Tab" tab viewing extension. It's idea was original (something different than all the Expose clones) but didn't work correctly on my dual monitors. I usually have FF on the second screen and that's where it didn't work. I removed it but it seems to have left my CTRL-Tab shortcut hijacked and I can't switch tabs.
I tried a couple of the "Popular" themes from addons.mozilla.org but they didn't really compare to Firefox's default theme which is excellent.
The only changes left that I wanted to make were to the Tab clicking options. The tabs now include a close X on each tab. I have mixed feelings about this. I've used Xs on tabs before I tend to accidentally close the tab that I am trying to switch to. This usually happens only when there are many tabs and the tabs are small. Also, I use the middle-click and double-click shortcuts to open and close tabs so an X just kind of takes up space.
I tried a tab options extension (I can't remember its name) which allowed me to remove all the Xs on tabs or just the Xs on background tabs but it didn't let me modify the tab clicking options. I am now using "Tab Clicking Options" instead. This doesn't let me get rid of Xs but it does let me set what middle and double click does to tabs. I don't understand why the default settings are double-click to close tabs and middle-click to open tabs.
I found that in about:config you can change a settings and remove the Xs on background tabs without an extension. There is also an option for disabling background close but it doesn't seem to prevent you from clicking the X on background tabs so I'm not sure what this setting is for.
I'm going to give the Xs a chance since I've heard that once you get used to them you like them. But I think middle-clicking will be hard to beat.
Thursday, October 19, 2006
XSS & SQL Inject solution
In a post (that I did not read completely through) on Tom Moertel's Weblog a solution for Cross-Site Scripting and SQL Injection vulnerabilities is discussed.
The idea is simple and I'm surpised it's not found in more places. He basically suggests that the type String is not good enough and that there are actually several sub-types of strings. These sub-types might include XML, SQL, and so on.
So the solution is to have a SqlString hold SQL text and a UserDataString hold user data. When these strings are combined the language could either take care of the proper escaping/conversion between string types or could throw a compile-time error about mis-matched string types.
I think in a language like C# you could create String classes that overload the Plus(+) operator and other String methods (e.g. ToString). However, I am a little stumped on type conversion/escaping of strings. It seems to me that each new String Type would have to know how to convert to each of the other String Types. But maybe that's just how it is. We use the Convert class for the same sort of thing for other types.
Any thoughts on this solution? How would this be implemented in a language like PHP or other loosely type language.
The idea is simple and I'm surpised it's not found in more places. He basically suggests that the type String is not good enough and that there are actually several sub-types of strings. These sub-types might include XML, SQL, and so on.
So the solution is to have a SqlString hold SQL text and a UserDataString hold user data. When these strings are combined the language could either take care of the proper escaping/conversion between string types or could throw a compile-time error about mis-matched string types.
I think in a language like C# you could create String classes that overload the Plus(+) operator and other String methods (e.g. ToString). However, I am a little stumped on type conversion/escaping of strings. It seems to me that each new String Type would have to know how to convert to each of the other String Types. But maybe that's just how it is. We use the Convert class for the same sort of thing for other types.
Any thoughts on this solution? How would this be implemented in a language like PHP or other loosely type language.
Monday, October 16, 2006
Natural Sort in C#
Natural or Human Sort is the very useful sort where the string "10" comes after the string "9" instead of before "9" and after "1".
If you have a list of files what are numbered you'll probably notice that Windows XP sorts these using a natural sort algorithm.
Useful languages like PHP have a natural sort as part of their base libraries. Unfortunately .Net did not get a natural sort comparer.
So, using http://sourcefrog.net/projects/natsort/ and http://www.mircscripts.org/showdoc.php?type=code&id=2771 as references I have created a Natural Sort compare algorithm in C#
If you have a list of files what are numbered you'll probably notice that Windows XP sorts these using a natural sort algorithm.
Useful languages like PHP have a natural sort as part of their base libraries. Unfortunately .Net did not get a natural sort comparer.
So, using http://sourcefrog.net/projects/natsort/ and http://www.mircscripts.org/showdoc.php?type=code&id=2771 as references I have created a Natural Sort compare algorithm in C#
#region Natural Sort
/// <summary>
/// Performs a natural sort order comparison of the strings. This can be used by CompareTo methods of
/// objects that want to be sorted. See: http://sourcefrog.net/projects/natsort/
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static int NaturalCompareTo(string a, string b)
{
// String is not an object and so this doesn't change the passed in value
a = a.ToUpper();
b = b.ToUpper();
int indexA = 0;
int indexB = 0;
int result = 0;
string aPart = " ", bPart = " ";
while (true)
{
aPart = indexA < a.Length ? a.Substring(indexA, 1) : "";
bPart = indexB < b.Length ? b.Substring(indexB, 1) : "";
while (IsSpace(aPart))
{
aPart = ++indexA < a.Length ? a.Substring(indexA, 1) : "";
}
while (IsSpace(bPart))
{
bPart = ++indexB < b.Length ? b.Substring(indexB, 1) : "";
}
if (IsDigit(aPart) && IsDigit(bPart))
{
if (aPart.Equals("0") || bPart.Equals("0"))
{
result = NatCompareLeft(a.Substring(indexA), b.Substring(indexB));
if (result != 0)
{
return result;
}
}
else
{
result = NatCompareRight(a.Substring(indexA), b.Substring(indexB));
if (result != 0)
{
return result;
}
}
}
if (IsEmpty(aPart) && IsEmpty(bPart))
{
return 0;
}
result = aPart.CompareTo(bPart);
if (result != 0)
{
return result;
}
indexA++;
indexB++;
}
}
private static bool IsDigit(string theValue)
{
if (theValue.CompareTo("0") >= 0 && theValue.CompareTo("9") <= 0 && theValue.Length == 1)
{
return true;
}
else
{
return false;
}
}
private static bool IsSpace(string theValue)
{
switch (theValue)
{
case " ":
case "\t":
case "\n":
case "\r":
case "\v":
case "\f":
return true;
default:
return false;
}
}
private static int NatCompareRight(string a, string b)
{
int bias = 0;
int index = 0;
string aPart, bPart;
while (true)
{
aPart = index < a.Length ? a.Substring(index, 1) : "";
bPart = index < b.Length ? b.Substring(index, 1) : "";
if (!IsDigit(aPart) && !IsDigit(bPart))
{
return bias;
}
else if (!IsDigit(aPart))
{
return -1;
}
else if (!IsDigit(bPart))
{
return 1;
}
else if (aPart.CompareTo(bPart) < 0)
{
if (bias == 0) bias = -1;
}
else if (aPart.CompareTo(bPart) > 0)
{
if (bias == 0) bias = 1;
}
index++;
}
}
private static int NatCompareLeft(string a, string b)
{
int index = 0;
string aPart, bPart;
while (true)
{
aPart = index < a.Length ? a.Substring(index, 1) : "";
bPart = index < b.Length ? b.Substring(index, 1) : "";
if (!IsDigit(aPart) && !IsDigit(bPart))
{
return 0;
}
else if (!IsDigit(aPart))
{
return -1;
}
else if (!IsDigit(bPart))
{
return 1;
}
else if (aPart.CompareTo(bPart) < 0)
{
return -1;
}
else if (aPart.CompareTo(bPart) > 0)
{
return 1;
}
index++;
}
}
#endregion
Thursday, October 12, 2006
The State of ClearType
Some time ago I installed the Microsoft Clear Type Tuning Tool. This tool allows you to configure your ClearType settings for the best appearing text.
Recently while developing some pages I noticed that some of my larger fonts looked pretty poor. After a little tweaking I noticed an interesting pattern.
No type anti-aliasing:

Standard type anti-aliasing:

ClearType type anti-aliasing:

You will notice that for large-sized fonts the Standard method looks better. However, for small sized fonts (fonts that are 1 pixel wide) the ClearType method looks better.
I can't understand why the "more advanced" ClearType anti-aliasing would produce such poor large fonts.
For web-design it doesn't really matter. I can't control how your computer is configured. I don't even know if you have the same fonts I've choosen. All I can do is try to make my design flexible and to make sure it looks good to the man who pays the bills.
All I can really do is decide which method I want to use. Bummer.
Recently while developing some pages I noticed that some of my larger fonts looked pretty poor. After a little tweaking I noticed an interesting pattern.
No type anti-aliasing:

Standard type anti-aliasing:

ClearType type anti-aliasing:

You will notice that for large-sized fonts the Standard method looks better. However, for small sized fonts (fonts that are 1 pixel wide) the ClearType method looks better.
I can't understand why the "more advanced" ClearType anti-aliasing would produce such poor large fonts.
For web-design it doesn't really matter. I can't control how your computer is configured. I don't even know if you have the same fonts I've choosen. All I can do is try to make my design flexible and to make sure it looks good to the man who pays the bills.
All I can really do is decide which method I want to use. Bummer.
Wednesday, October 11, 2006
Javascript Closures
Editors Note: I had this all edited and fixed up and then something funny happened and I lost it all. So you're getting the unedited version. I'm not doing it again and nobody reads this blog yet anyhow.
Javascript can be a frustrating language. At first it seems like BASIC with a C syntax. But quickly odd things start happening. They aren't really odd but they aren't what you expect. In order to do my part to save the world from odd things I present some thoughts on Javascript Closures. I recommend reading Javascript Closures by Richard Cornford.
Many of the odd things in Javascript begin to manifest themselves when you begin embedding functions inside other functions. This happens a lot when you dynamically assign event handlers to objects on a web page. These thoughts are mostly in that context.
Closures
Closures have to do with the way Javascript supports scoping in nested functions. A nested function has access to the scope of its parent functions. However, the scope of the parent functions can change after the nested function has been declared and before the nested function is actually called and executed.
It's common to assume that the nested function gets the parent scope when it is declared. But this is not the case. The parent scope is checked when the nested function is called. This also means the parent scope continues to exist after the parent function has ended.
Examples:
This example shows that the function child checks the parent function scope when it is called, and so alerts "Parent Variable After" at the second call. A common mistake is to assume that the child function will always alert "Parent Variable Before" since it was declared when parentVariable was set to that value.
This misconception causes trouble when trying to set onclick events in a for loop. The code usually looks something like this:
In this example 10 divs are created. Each is numbered from 1 to 10. When you click each on you would expect the div to alert with its number. It does not. The alert displays 10 on all the divs.
This behavior makes sense if you think about the scope of the parent function and when the child (the onclick) function is being called versus when it is being declared. The child function does not use the parent scope when it is declared. It hasn't actually been executed yet. By the time it is called the parent scope (and the variable i has changed.
By the time you click a div and the onclick is called the i variable in the parent scope is set to 10 because the loop has finished and stopped at 10. If you add the line below after the for loop then each click on a div will display "Hello World". So, understanding the parent scope what did you expect? It's using the parent scope at the time of the click, not the scope when the onclick function was declared.
Here is another example. You should be able to predict the behavior without running the script.
So, without running the script, will the call to my_function alert with a 5 or a 10? If you said 5 then shame on you. You'd better start again.
A Solution
It's not uncommon to want to assign event functions in a loop (like the onclick div example). But the obvious code example above doesn't do what you might expect (although it does do the right/correct thing). So, in order to make it work you need to either create a scope that's not going to change between the time you declare the inline function and the time you call the inline function or you could declare a variable that is not going to change in the parent scope. You can't use i because it's going to change each time you loop.
I use the the "create a scope" method. The only way I know to create a new scope in javascript is by calling in to a function.
(in Javascript loops do not have their own scope. Their variables are elevated to the existing scope so you can't use any kind of nested for. That is why i == 10 and not undefined in our div example above. Even though the i was declared in the for-loop, Javascript promotes it to the function's scope and it still exists after the loop has ended).
Javascript can be a frustrating language. At first it seems like BASIC with a C syntax. But quickly odd things start happening. They aren't really odd but they aren't what you expect. In order to do my part to save the world from odd things I present some thoughts on Javascript Closures. I recommend reading Javascript Closures by Richard Cornford.
Many of the odd things in Javascript begin to manifest themselves when you begin embedding functions inside other functions. This happens a lot when you dynamically assign event handlers to objects on a web page. These thoughts are mostly in that context.
Closures
Closures have to do with the way Javascript supports scoping in nested functions. A nested function has access to the scope of its parent functions. However, the scope of the parent functions can change after the nested function has been declared and before the nested function is actually called and executed.
It's common to assume that the nested function gets the parent scope when it is declared. But this is not the case. The parent scope is checked when the nested function is called. This also means the parent scope continues to exist after the parent function has ended.
Examples:
function parent() {
var parentVariable = "Parent Variable Before";
function child(childVariable) {
var childVariable2 = "Child Variable 2";
alert(parentVariable);
alert(childVariable);
alert(childVairable2);
}
child("Child Variable");
parentVariable = "Parent Variable After";
child("Child Vairable");
}
This example shows that the function child checks the parent function scope when it is called, and so alerts "Parent Variable After" at the second call. A common mistake is to assume that the child function will always alert "Parent Variable Before" since it was declared when parentVariable was set to that value.
This misconception causes trouble when trying to set onclick events in a for loop. The code usually looks something like this:
for (var i=1; i <= 10; i++) {
var new_element = document.createElement("div");
new_element.onclick = function (e) { alert(i); };
new_element.innerHTML = i;
document.appendChild(new_element);
}
In this example 10 divs are created. Each is numbered from 1 to 10. When you click each on you would expect the div to alert with its number. It does not. The alert displays 10 on all the divs.
This behavior makes sense if you think about the scope of the parent function and when the child (the onclick) function is being called versus when it is being declared. The child function does not use the parent scope when it is declared. It hasn't actually been executed yet. By the time it is called the parent scope (and the variable i has changed.
By the time you click a div and the onclick is called the i variable in the parent scope is set to 10 because the loop has finished and stopped at 10. If you add the line below after the for loop then each click on a div will display "Hello World". So, understanding the parent scope what did you expect? It's using the parent scope at the time of the click, not the scope when the onclick function was declared.
i = "Hello World";
Here is another example. You should be able to predict the behavior without running the script.
var my_function;
for (var i=1; i <= 10; i++) {
if (i == 5) {
my_function = function() { alert(i); };
}
}
my_function();
So, without running the script, will the call to my_function alert with a 5 or a 10? If you said 5 then shame on you. You'd better start again.
A Solution
It's not uncommon to want to assign event functions in a loop (like the onclick div example). But the obvious code example above doesn't do what you might expect (although it does do the right/correct thing). So, in order to make it work you need to either create a scope that's not going to change between the time you declare the inline function and the time you call the inline function or you could declare a variable that is not going to change in the parent scope. You can't use i because it's going to change each time you loop.
I use the the "create a scope" method. The only way I know to create a new scope in javascript is by calling in to a function.
(in Javascript loops do not have their own scope. Their variables are elevated to the existing scope so you can't use any kind of nested for. That is why i == 10 and not undefined in our div example above. Even though the i was declared in the for-loop, Javascript promotes it to the function's scope and it still exists after the loop has ended).
function SetOnClick(value) {
// A new scope is created when this function is called
return function(e) { alert(value); };
// Once the function exits value can never be changed again.
// So when this inline function is called we can be assured that value will still be the same
}
for (var i=1; i<=10; i++) {
var new_element = document.createElement("div");
new_element.onclick = SetOnClick(i); // Now this onclick gets the inline function returned by SetOnClick.
// Calling this function creates the new scope we need
new_element.innerHTML = i;
document.appendChild(new_element);
}
Tuesday, October 10, 2006
Javascript Variables
Introduction
It amazes me how long I have been coding little bits and copy/pasting scripts in Javascript without really knowing how it is really working. Javascript is a deceptive language. It just comes with the browser. You use little one or 2 liners to make a roll-over, open a window, change statusbar text. Then you try something more complex. Weird things happen. You work around (more like 'stumble around') bugs.
Javascript is pretty different. It pays to find a good reference and approach the language in a Computer Science kind of way. Don't be a doofus web designer like me and just stumble around.
Interesting bit
There aren't really any global variables. Child functions just have access to their parent scopes.
So this:
doesn't really access a global variable. It's really like this (you just don't see it):
All those global variables, classes, and functions are attached to an object. I'm pretty sure it's the window object.
Loops don't have their own scope & Variable declarations are moved to the top
Javascript doesn't give a loop its own scope. It moves all variable declarations to the top of the function. For example:
is the same as (and becomes at runtime)
That's why you don't get an error when alerting i and k. Since the second snippet is what acutally gets executed i and k are actually in scope of the function the whole time. There is not loop scope. You could alert on i and k before the loops as well. You'll get undefined for a value though since they aren't assigned anything until the loop starts.
Undeclared variables
Javascript is very forgiving. So much so that if you don't declare a variable, but still access it, the variable is declared for you. But it may not be in the scope that you think. Try this:
Surpised? I was. The am_i_local variable is first accessed and assigned in my_function1 but is still accessible to my_function2. Sounds like a global. Add var in front of am_i_local and see what happens. You will get an error when my_function2 is called. A var statement declares the variable locally in my_function1 making it non-existant in my_function2's scope.
Okay, so what about undeclared variables in nested functions? Take a look at this:
I get 2 alerts and no errors. So, undeclared variables get a global scope, not just the parent scope. If you add var to am_i_inner you'll get errors. I'm not sure which global scope, but I'd assume they are in the same scope as other global variables. In fact you can walk the global object, which I believe is window and see that am_i_inner is a property of it. Just add this to the end of the script:
So you see, everything I said is true (or appears to be). There aren't really any globals. Everything you do is really just nested in a parent object which looks likes it's the Window object. Javascript is forgiving and declares the variables that you forget to declare as "global". Really it's doing the same thing with the functions declare. For example:
Both function declarations do the same thing.
Disclaimer:
For all I know I am blowing southern hot air. So, until someone instructs me otherwise, this is how I understand Javascript variables and scope. You'll want to learn a bit about Javascript closures to gain a deeper understanding of Javasript's behavior.
It amazes me how long I have been coding little bits and copy/pasting scripts in Javascript without really knowing how it is really working. Javascript is a deceptive language. It just comes with the browser. You use little one or 2 liners to make a roll-over, open a window, change statusbar text. Then you try something more complex. Weird things happen. You work around (more like 'stumble around') bugs.
Javascript is pretty different. It pays to find a good reference and approach the language in a Computer Science kind of way. Don't be a doofus web designer like me and just stumble around.
Interesting bit
There aren't really any global variables. Child functions just have access to their parent scopes.
So this:
var a_global_variable = "Hello World";
function a_function() {
alert(a_global_variable);
}
doesn't really access a global variable. It's really like this (you just don't see it):
function virtual_root_function() {
var local_root_variable = "Hello World";
function a_function() {
alert(local_root_variable);
}
}
All those global variables, classes, and functions are attached to an object. I'm pretty sure it's the window object.
Loops don't have their own scope & Variable declarations are moved to the top
Javascript doesn't give a loop its own scope. It moves all variable declarations to the top of the function. For example:
function my_function() {
var local1 = "hello";
for (var i=0; i<10; i++) {
var y = i;
}
var j = 0;
while (j < 100) {
var k = j + 2;
j = k + 1;
}
alert(i);
alert(k);
}
is the same as (and becomes at runtime)
function my_function() {
var local1 = "hello";
var i = 0;
var y;
var j = 0;
var k;
for (i=0; i < 10; i++) {
y = i;
}
while (j < 100) {
k = j + 2;
j = k + 1;
}
alert(i);
alert(k);
}
That's why you don't get an error when alerting i and k. Since the second snippet is what acutally gets executed i and k are actually in scope of the function the whole time. There is not loop scope. You could alert on i and k before the loops as well. You'll get undefined for a value though since they aren't assigned anything until the loop starts.
Undeclared variables
Javascript is very forgiving. So much so that if you don't declare a variable, but still access it, the variable is declared for you. But it may not be in the scope that you think. Try this:
function my_function1() {
am_i_local = "Am I local to my_function1?";
}
function my_function2() {
alert(am_i_local);
}
my_function1();
my_function2();
Surpised? I was. The am_i_local variable is first accessed and assigned in my_function1 but is still accessible to my_function2. Sounds like a global. Add var in front of am_i_local and see what happens. You will get an error when my_function2 is called. A var statement declares the variable locally in my_function1 making it non-existant in my_function2's scope.
Okay, so what about undeclared variables in nested functions? Take a look at this:
function my_function1() {
var inner1 = function() {
am_i_inner = "Do I exist only in inner1?";
}
var inner2 = function() {
alert(am_i_inner);
}
inner1();
inner2();
}
function my_function2() {
alert(am_i_inner);
}
my_function1();
my_function2();
I get 2 alerts and no errors. So, undeclared variables get a global scope, not just the parent scope. If you add var to am_i_inner you'll get errors. I'm not sure which global scope, but I'd assume they are in the same scope as other global variables. In fact you can walk the global object, which I believe is window and see that am_i_inner is a property of it. Just add this to the end of the script:
for (p in this) {
document.writeln(p + ": " + this[p] + "<br />");
}
So you see, everything I said is true (or appears to be). There aren't really any globals. Everything you do is really just nested in a parent object which looks likes it's the Window object. Javascript is forgiving and declares the variables that you forget to declare as "global". Really it's doing the same thing with the functions declare. For example:
function my_function() {
alert("Hello World!";
}
this.my_function = function() {
alert("Hello World!");
}
Both function declarations do the same thing.
Disclaimer:
For all I know I am blowing southern hot air. So, until someone instructs me otherwise, this is how I understand Javascript variables and scope. You'll want to learn a bit about Javascript closures to gain a deeper understanding of Javasript's behavior.
Friday, October 06, 2006
Harry Potter -- Fact or Fiction?
I've never really understood all the debate over works of fiction. I'm not talking about whether Book Y should be banned from School X. I'm talking about all the fans that argue whether Hero A met Villian Z in highschool. Fans arguing over one point or another. It's NOT REAL! It didn't happen. There is no history. Author M just made it all up. You might call it a big lie.
So, you can argue the points in the book. That's fine and dandy. But we really don't know if Lily Evans and James Potter were born in the same hospital and thus destined to be Harry Potter's parents who will eventually become leader of a radical movement of Aurors which brings down the corrupted Ministry of Magic in Book 32: Harry Potter and the Revolting Aurors.
I've read the Harry Potter books several times. I've seen and own the movies (and liked them less than the books but I'm a modern man without enough time for all my entertainment and movies are a relatively quick fix). I enjoy the story and discussing decisions made and their consequences. And I am dumbfounded every time I hear news of the various disputes over the books, factual or fictitious.
I just don't get it.
Be the way, I read this today and got a good chuckle: http://www.slate.com/id/2150585/
So, you can argue the points in the book. That's fine and dandy. But we really don't know if Lily Evans and James Potter were born in the same hospital and thus destined to be Harry Potter's parents who will eventually become leader of a radical movement of Aurors which brings down the corrupted Ministry of Magic in Book 32: Harry Potter and the Revolting Aurors.
I've read the Harry Potter books several times. I've seen and own the movies (and liked them less than the books but I'm a modern man without enough time for all my entertainment and movies are a relatively quick fix). I enjoy the story and discussing decisions made and their consequences. And I am dumbfounded every time I hear news of the various disputes over the books, factual or fictitious.
I just don't get it.
Be the way, I read this today and got a good chuckle: http://www.slate.com/id/2150585/
Tuesday, October 03, 2006
Getting the Identity after an Insert
In developing web applications I've often needed to get back a record's ID immediately after inserting it. Each database has its own method. This is the Microsoft SQL Server method I use.
Now retrieve "newid" from the database result set.
The SQL uses the safe 'scope_identity' function to get the most recent identity value for your connection. Then it casts it do an Int. If you don't do this it will come back as a Double and you have to cast it back to an Int32. Using the case we can just call GetInt32 in the Data Reader.
INSERT INTO [TABLE](COLUMN) VALUES (@value)
SELECT CAST(scope_identity() AS INT) AS newid
Now retrieve "newid" from the database result set.
The SQL uses the safe 'scope_identity' function to get the most recent identity value for your connection. Then it casts it do an Int. If you don't do this it will come back as a Double and you have to cast it back to an Int32. Using the case we can just call GetInt32 in the Data Reader.
It's the little moments...
In the car pool we are listening to the "Harry Potter and the Order of the Phoenix" book on tape (I'm sure that violates all sorts of copyrights but that's for another rant). We tend to fast-forward through much of it as the author seems to ramble on and on. This morning Harry bumped in to Choe. Her friend had snitched on the DA. Harry was fairly rude and Choe got upset. This scene represents the end of their relationship.
We remarked on how unimportant the scene seems compared to the other events occuring in the story at the time (Umbridge has just become Headmaster and the Twins are causing much havoc).
This led us to a moments thought about how seemingly insignificant choices can change the direction of our entire life.
The common analogy is a compass (a comparison which makes sense to me). Big decisions are like big turns and they change our heading significantly and our direction in life. Small decisions are like little 1 degree turns. After a short distance we don't see any difference but after a lifetime we will be in a much different place that we would have been.
We remarked on how unimportant the scene seems compared to the other events occuring in the story at the time (Umbridge has just become Headmaster and the Twins are causing much havoc).
This led us to a moments thought about how seemingly insignificant choices can change the direction of our entire life.
The common analogy is a compass (a comparison which makes sense to me). Big decisions are like big turns and they change our heading significantly and our direction in life. Small decisions are like little 1 degree turns. After a short distance we don't see any difference but after a lifetime we will be in a much different place that we would have been.
Monday, October 02, 2006
Digg & Reddit
I've become slightly addicted to Digg and Reddit. I don't recommend these sites but they are filling this sick need for new ways to waste time on the Internet. The Internet is my real addiction. Thank goodness there aren't withdrawal symptoms when I go on vacation.
Digg and Reddit are good ideas and it will be insteresting to see if they make it in the long run. I think it takes a certain demographic to make them run. Both sites are full of political rants and arguments for one point of view or the other. It's almost enough to drive me away.
I visit these sites looking for the few tidbits that interest me. Something about the latest in PC gaming. Something about the Wii. Or something funny, sexy, or stupid. Anything but politics. I want to care, but in the midst of all the bickering and arguing I just can't. I feel a duty to care, but it's all so silly and biased. It's sad that these clowns waste so much time and money on it all. What's worse is that part of it is my money!
Anyways, back to community link sites. I could probably search out blogs and grab feeds and build a great list of what I'm interested in, but I'm lazy and Digg is a quick fix. I think the next step in news aggregation will be feeds of feed aggregates. If I can find a few people with similar interest then I can just pull their aggregated feeds together. I'll get my quick fix and relevant information.
Digg and Reddit are good ideas and it will be insteresting to see if they make it in the long run. I think it takes a certain demographic to make them run. Both sites are full of political rants and arguments for one point of view or the other. It's almost enough to drive me away.
I visit these sites looking for the few tidbits that interest me. Something about the latest in PC gaming. Something about the Wii. Or something funny, sexy, or stupid. Anything but politics. I want to care, but in the midst of all the bickering and arguing I just can't. I feel a duty to care, but it's all so silly and biased. It's sad that these clowns waste so much time and money on it all. What's worse is that part of it is my money!
Anyways, back to community link sites. I could probably search out blogs and grab feeds and build a great list of what I'm interested in, but I'm lazy and Digg is a quick fix. I think the next step in news aggregation will be feeds of feed aggregates. If I can find a few people with similar interest then I can just pull their aggregated feeds together. I'll get my quick fix and relevant information.
Convert Excel Dates to Text
Interesting bit:
=IF(ISBLANK(A1), "", IF(ISERR(DATEVALUE(A1)), TEXT(A1, "mm/dd/yyyy"), A1))
Issue:
Frequently I am sent an Excel file full of data. It is almost guaranteed to have a date column. And almost always this column has a mix of Excel Dates, text, and blank entries.
The file looks fine, but at my level looks don't matter. I am trying to manipulate the data. Internally Excel sees dates and as an integer. This integer represents "so many units since some date" and is pretty useless when imported in to a database or converted to a CSV file.
I need to convert this date to a text value. Some of the value only appear as dates but are really text strings (not integers) and so the function has to ignore those.
=IF(ISBLANK(A1), "", IF(ISERR(DATEVALUE(A1)), TEXT(A1, "mm/dd/yyyy"), A1))
Issue:
Frequently I am sent an Excel file full of data. It is almost guaranteed to have a date column. And almost always this column has a mix of Excel Dates, text, and blank entries.
The file looks fine, but at my level looks don't matter. I am trying to manipulate the data. Internally Excel sees dates and as an integer. This integer represents "so many units since some date" and is pretty useless when imported in to a database or converted to a CSV file.
I need to convert this date to a text value. Some of the value only appear as dates but are really text strings (not integers) and so the function has to ignore those.
Subscribe to:
Posts (Atom)