Saturday, May 30, 2009

HTML 5

The recent buzz over HTML 5 this week at Google I/O could not have come at a better time.

It reminds me of another time, back in 2005, when the economy was just starting to recover from the dotcom bust. Ajax made the scene (heavily backed by Google in the form of Suggest and Maps) and got people excited about doing cool things on the web again.

Now the economy is in the crapper again, and here comes HTML 5 (again backed by Google in the form of Chrome and Wave). Looking at some of the demos, I feel the same exhilaration I once felt when I first recognized the potential of DHTML. In many ways, HTML 5 picks up where DHTML -- or DOM scripting of whatever -- left off long ago.

I offer no analysis. It's the most excited I've been about web development in years.

Tuesday, February 03, 2009

Constraining elements to the browser window

I recently worked on a demo that used tooltip-like "popover" menus that appeared when the mouse pointer hovered over certain page elements. The initial approach was pretty straightforward: find the offsetTop and offsetLeft of the target element, then move the menu to those coordinates.

Two challenges:

  • If an item was too close to the left or bottom edge of the browser window, the menu would appear partially offscreen. So I had to figure out how to constrain the menu to the visible window area.
  • I had to account for any additional window scrolling.

The following seemed to do the trick. Note that this is pseudo-JavaScript; I leave it to you to figure out how to actually obtain the necessary values and make the appropriate substitutions.

// element = target element that gets the menu
// menu = the menu popover DIV

var bottomEdge = element.offsetTop + menu.height - document.scrollTop;
if ( bottomEdge > window.height )  {
    menu.top = element.offsetTop - (bottomEdge - window.height);
}

var leftEdge = element.offsetLeft + menu.width - document.scrollLeft;
if ( leftEdge > window.width)  {
    menu.left = element.offsetLeft - (leftEdge - window.width);
}

Wednesday, November 12, 2008

Does your website disappear in IE8?

Mine did.

I was recently given a pretty large redesign project, and during the planning stages I took the opportunity to add a long-missing DOCTYPE to the site. I chose a nice HTML 4.01 Transitional flavor because there was no way in hell the site was going to resemble anything close to XHTML anytime soon. At the very least, it would 1) get the site out of quirks mode, and 2) give us an eventual path to validation.

(I'm including this info to illustrate: we had a proper DOCTYPE, and knew the site would not be valid HTML going in.)

Months after the project was complete and launched, word came down that the site was missing in IE8. Not broken. MISSING. Like, "the page is blank."

No partial loading, no sudden flicker, no error message. The site simply would not render.

I was considering hard liquor as my preferred solution when one of my co-workers mentioned something he'd heard about a new META element, something about versioning. Ah, yes, that version targeting thing.

I added the following to the global website header:

<meta http-equiv="X-UA-Compatible" content="IE=7" />

...and suddenly the site worked in IE8.

This is not a "solution." I still don't know why the site vanishes in IE8. I mean, it rendered perfectly fine in IE5, IE5.5, IE6 and IE7 so OF COURSE IT MAKES TOTAL SENSE THAT IT COMPLETELY VANISHES IN IE8. Right?

No. It does not make sense. Anyway, when I do discover the root cause, I'll post it here. In the meantime, I guess I'll be asking IE8 to dumb it down to my level.

Thursday, July 17, 2008

Missing form ACTIONs

Say you want to disable a submit button when it's clicked, to prevent the user from submitting twice:

<form name="myform">
  <input type="submit" value="Submit" onclick="this.disabled = 'true';">        
</form>

On Windows, this works fine in IE but not in Firefox. Or so it appears. What's going on?

Oops, you forgot an ACTION attribute in your form. (It's okay, this is common if you're planning an Ajax-style app.) Without it, IE just ignores the submit click, but Firefox uses the current page as the default action. So it effectively reloads the page, resetting the button state.

The thing is, the submit button is being disabled in FF, just like in IE, but depending on how fast the page reloads, you might not even notice.

Wednesday, July 16, 2008

Function reference vs. function call

Here's a JavaScript function definition:
function foo() {
  alert('foo!');
}
You can refer to that function like this:
foo
And here is how to call (execute) the function:
foo()
Even experienced developers new to JS tend to get these confused. For example, jQuery's getJSON method allows you to specify a function to be executed once the operation is complete. Be careful not to plug in the function call when what you really need is a function reference:
$.getJSON( "action.php", {data:'some data here'}, foo() );
This will execute the foo function instantly. Not what you want. So leave off the parens:
$.getJSON( "action.php", {data:'some data here'}, foo );
This merely passes a reference to the function. It won't execute until it's called by jQuery.

Wednesday, April 16, 2008

A good enough addEvent

O HAI, this blog is nearly dead these days. But before it truly shuffles off into the sunset, allow me to point you to filosofo's "good enough" addEvent. Austin gets around PPK's pesky requirements by ignoring one of them (namely, having a corresponding removeEvent).

I love this solution because it mirrors much of my recent experiences with JavaScript. Honestly, I can't remember the last time I needed anything more than some variation of toggle() and I can count on one hand the number of times I've need to detach an event since 1998.

Kudos to Austin for thinking differently.

Sunday, July 01, 2007

Some reader contributions to Calendar tutorial

When I started SZOJ I promised myself I wouldn't abruptly shut down the blog if I lost interest; I'd just go radio silent until my interest was piqued again. That said, it's been a long while. So here are two things:

Rory Parle wrote in to point out you can use Math.ceil to determine the number of rows you'd need to safely render a calendar:

Math.ceil((monthLength + startingDay) / 7);

Michiel van der Blonk suggested a way to determine the number of days in a month:

var d = new Date(nYear, nMonth + 1, 0); // nMonth is 0 thru 11
return(d.getDate());

The mechanism here is the Date constructor will attempt to convert year, month and day values to the nearest valid date. So in the above code, nMonth is incremented to find the following month, and then a Date object is created with zero days. Since this is an invalid date, the Date object defaults to the last valid day of the previous month — which is the month we're interested in to begin with. Then getDate() returns the day (1-31) of that date — voilá, we have the number of days.

Bonus: it also seems to automatically correct for leap year. It feels like a hack but it seems to work consistently.

Thanks to Rory and Michiel for their contributions.