No Mod Required

Archive for the 'javascript' Category

A Small Site Enhancement

I made the image in my gallery pages "hot" today. Each gallery image now points to the next image in the gallery flow. It'll be interesting to see if that increases the average number of page views per user. I'm thinking it will as a lot of people use that technique so I'll hopefully be leveraging that learned behavior. Logically it just makes sense as those back, home and next buttons are way too small. I'll report the results in a couple of weeks…

Check it out here.

I'm actually in the process of recoding all the gallery pages (with the exception of the alphabet I posted yesterday, which was built that way from the beginning) to have an actual anchor tag wrapped around the image. For now I'm doing it with a little bit of JavaScript:


var imgs = $("artimg").getElementsByTagName("img");
for (var i=0; i< imgs.length; i++) {
    imgs[0].onclick= function() {
        document.location.href=$("next").href;
    }
}

where "next" is the existing ID applied to the next link in gallery pages. I love being able to use such simple JavaScript to enhance the user experience in such a (potentially) large way.

Internet Explorer 8 Is a Day Old and I'm Already (kinda) Frustrated.

I'm kidding of course, my overall initial reaction is actually quite positive. For instance, I just saw it do this:

ie-8-acid2-test.jpg

That promises good things in my future :)

Still, looking at my site, I'm presented with my very first Internet Explorer 8.0 Mystery ™

I use opacity to do the image replacement in my logo. As the following image shows, neither of the two techniques I'm familiar with to set opacity work in IE8:

opacity-fails.jpg

The Internet Explorer filter:


#logo a {
filter:Alpha(opacity=0)
}

and the CSS3 Color Module color property:


#logo a {
opacity:0
}

both fail.

The Google tells me nothing and searching MSDN also turns up nothing, so I'm left to grapple with my first "what the?!?" of the IE8 Era…

Where oh where has my opacity gone?
Where on Earth can it be?

I'm going to keep at it, since I do use opacity often enough to turn this into an official "issue" for me. To that point, if anyone out there has any idea what's up with opacity and IE8, I'd love to hear about it.

Mark Pilgrim on Douglas Crockford's "Fixing HTML"

The difference, of course, is that Crockford should understand that things are a little more complicated than that, but the ideas that he thinks are good enough to announce to the world are no better than the ideas a 5-year old has before breakfast. “No more iframes! No more document.write!” he declares, blissfully unaware that his employer’s home page uses both. “Strict entity parsing!” he demands… in a page with unescaped ampersands. “UTF-8 is the One True Encoding!” he proclaims boldly… in a page that declares itself as ISO-8859-1. “No more javascript: URLs! In fact, let’s replace Javascript altogether! And I’ll be back to talk about CSS!” It just goes on and on, the awesomeness gradually swelling until it all folds back on itself like a Möbius strip of self-parody. It’s the Bolero of trolls. Everything he claims is secure isn’t, and everything he claims would increase security wouldn’t. Everything he wants to add to HTML would make it worse, and everything he wants to remove would also make it worse. Please, please tell me he’s shooting the moon to make the worst proposal ever. It just doesn’t make sense any other way, at least not from anyone older than 5.

The Bolero of trolls [dive into mark]

The Fixing HTML page itself.

Books 2008 #3 Pro JavaScript Design Patterns

Pro JavaScript Design Patterns An excellent book. There are plenty of takeaways from this intense examination of Object Oriented programming in JavaScript. I haven't worked on a project large enough to really benefit from OO JavaScript in the overall (classes/inheritance, etc), but even without switching over to a fully OO framework, there are optimization patterns and namespace patterns outlined in this book that can immediately prove useful no matter what scale of project you're working on.

From a pure "oh, that's cool!" perspective, the chapter on Chaining was a real eye opener. I'd looked at jQuery code, of course, but I'd never sat down to think about how he might have created the().ability().t0().keep().mashing().functions().together(). It's diabolically simple in concept (return this!), but also mighty powerful. Again, it's not one of the patterns I'm looking to adapt any time soon, but it was crazy interesting how simple it is in concept.

Two CSS Techniques I Love + I Rolled My Own Social Bookmarking Component

I used to use AddThis for social bookmarking here on the blog. And by "used to" I mean up until two days ago :-). Over the past couple of days I've been working on setting up my own version to use here and throughout the rest of the site. I launched it yesterday.

If you're on the single version of this post (as opposed to a category index or the blog home page) you should see it in all its simple glory below in the post info box.

Why bother since AddThis does what it's supposed to do and is dead easy to implement? Well, while the number isn't really important (only the underlying performance issues it uncovers really matter) it was pointed out recently that I (used to) get a 61 YSlow score for my blog pages (thanks Ben!) One of the contributing factors to that was the use of the AddThis widget which added another domain lookup and several extra HTTP requests for uncompressed files with no expires headers. I looked at all that overhead and inefficiency, looked at the functional complexity (or lack thereof) of the piece and decided I would just roll my own. Beyond the fact that it was just a fun little thing to do, doing my own saved 16 HTTP requests (including 13 Images,) removed a domain lookup and required a total of 0 (zero) extra files to implement. How? I obviously used my existing JS and CSS files and (most importantly) added the icons to my sprite. Those already come along with the page so it's just an extra 1-2K of image and script on top of my existing site infrastructure.

I didn't do anything particularly fancy (there's always time for that later :)), but if you're curious here's the basics of the implementation.

Here's the WordPress code, where we use the_permalink() and the_title() to build out the links:

<div class="shareThis">
Share This :  <a href="http://del.icio.us/post?url=<?php the_permalink(); ?>&title=<?php the_title(); ?>" class="delicious" title="save to delicious">Del.icio.us</a>
<a href="http://digg.com/submit?phase=2&url=<?php the_permalink(); ?>&title=<?php the_title(); ?>" class="digg-this"  title="digg this!"> Digg</a> 
<a href="http://reddit.com/submit?url=<?php the_permalink(); ?>&title=<?php the_title(); ?>" class="reddit"  title="submit to reddit">Reddit</a> 
<a href="http://www.stumbleupon.com/submit?url=<?php the_permalink();  ?>&title=<?php the_title(); ?>" class="stumble"  title="stumble this!">Stumble It</a> 
<a href="http://www.facebook.com/sharer.php?u=<?php the_permalink();  ?>&t=<?php the_title(); ?>" class="facebook"  title="share on facebook">Facebook</a>
</div>

I chose those five because they were (a) amongst the most popular choices I saw in my AddThis stats and (b), with the exception of Facebook, they have all produced serious traffic spikes here. Facebook has never actually driven a lot of traffic for me, but it was a regular option in AddThis so I included it here.

As for the markup- as you can see, it's pretty stripped down. All I use are some anchors and a div to hold them. I then use a couple of common (for me) CSS techniques to get that stripped down markup styled up correctly. Here's the CSS:

.shareThis {
font-size:85%;
font-weight:bold;
color:#666;
background: url(http://media.drunkenfist.com/img/sprite2.png) -315px 0 no-repeat;
/*set position to relative in order to 'catch' child nodes at this level*/
position:relative;
padding:2px;
border:1px solid #ccc;
width:175px;
height:15px;
margin:auto;
margin-top:5px;
}
#moviespg  .shareThis,
#grafpg .shareThis,
#comicspg .shareThis,
#artpg  .shareThis{
/*there's a slightly different context for this widget on the rest of the site*/
font-size:75%;
}
.shareThis a {
/*I love absolutely positioned anchors with display:block*/
/*I use them all the time*/
position:absolute;
width:15px;
height:15px;
/*hide the text*/
/*I might switch this to opacity if the outlines bug me*/
text-indent:-9999px;
top: 2px;
}
/*position the individual anchors on top of their icons*/
/*this is like a new style 'image map'*/
.shareThis a.digg-this {
left:92px;
}
.shareThis a.delicious {
left:110px;
}
.shareThis a.facebook {
left:165px;
}
.shareThis a.reddit {
left:129px;
}
.shareThis a.stumble {
left:147px;
}
.shareThis a:hover {
/*hide the default hover since it obscures the icon*/
background:transparent url() !important;
/*safari didn't like the above, so I threw a little opacity in there*/
opacity:0;
}

I'll break out two of my favorite techniques in play.

Position:relative with no offset and absolutely positioned child nodes

The key with this technique lies in the behavior of absolutely positioned elements and the way that relatively positioned elements behave when there are no position coordinates (top, left, right, bottom) supplied.

Absolutely positioned elements search for the first parent element with a position other than static to begin to calculate it's positining. In the above example that's the containing div. The thing is, the containing div, while set to position:relative, has no offset coordinates supplied to it, which means it behaves exactly as if it were the default, static positioning. In other words it's still firmly in the normal flow of the document.

In the situation above the benefits of that might not be all that evident, but imagine this layout:

so-easy.png

With the middle content div set to position:relative and the two sidebars set to position: absolute inside of it, that layout can be achieved with a minimum of fuss. The header, content and footer DIVs are just in the normal flow. They will expand and contract as needed and won't need any special handling to grow as long as might be needed by the site content or any conditional messaging. The content DIV is set with enough internal padding set to accommodate the sidebars and the sidebars, as long as they don't need to control the height of the document, can be placed with pixel perfection wherever they need to go. No need to mess with floated content or anything fussy like that. Just two nice and stable absolutely positioned elements mixed with a normal block item document flow that would have worked in 1999. That layout will produce very few surprises.

Of course, if the layout requires two or more of the columns to be able to control the height then this technique is invalid, but if it's as simple as the one above, go nuts.

Another place I use that technique is with headers or mastheads. Headers often have three elements- a logo, a main menu and a utility menu. With that layout I will use a relatively positioned div for the container and then place three absolutely positioned items inside for the three elements: an image replaced header (h1, h2) for the logo, and two unordered lists for the two menus. The markup might look something like this:


<div id="header">
   <h1><a href="/" title="return to the home page">Our Company Name</a></h1>
   <ul id="main-menu">
      <li>menu item</li>
      <li>menu item</li>
      <li>menu item</li>
   </ul>
   <ul id="utility-menu">
      <li>menu item</li>
      <li>menu item</li>
     <li>menu item</li>
   </ul>
</div> 

And would render something like this:

common-header.jpg

So straightforward and it allows me to move things around with perfect precision.

Modern "Image Maps"

This ties in with the above but focuses entirely on using anchors as absolutely positioned block level elements to create "hot spots" in much the same manner old school image maps do. In the High Performance Web Sites book, Steve Souders talks about talk about using image maps to reduce HTTP Requests. While from a performance perspective that's a valid approach, image maps as a whole are out of favor and are rarely (if ever) a technique I'll look to use.

The following is a somewhat more accessible, SEO friendly method of achieving the same result.

A note about the example above, before I point out one that's a little more along the lines of my normal usage of this technique.

While I definitely like to use unordered lists as a container for menus and the like, there are plenty of situations where there's really no need for a containing framework. While in this example you could make an argument that I should have a list around the links (it's a list of links after all,) my first concern with this component was to create something really stripped down code-wise. I was trying to improve performance after all, so I went with the least code possible, sacrificing some potential semantic meaning in the process.

If I weren't flexible about these things I'd have to quit my day job and go work for a standards body :)

Anyway, the following image and code sample will outline a really useful implementation of this technique.

Here's some HTML:

<div class="messaging">
     <h2>The Toughest Challenges, The Most Interesting Ideas</h2>
     <a href="/register-now">register now</a>
</div>

Here's some CSS:

#copy .messaging h2 {
text-indent: -9999px;
height: 211px;
width: 778px;
position:relative;
}

#copy .messaging a {
position: absolute;
display:block;
text-indent:-9999px;
left: 200px;
top:150px;
height:28px;
width:140px;
}

And this is what it all looks like:

anchor-highlighted.jpg

As you can see with the red highlight, the absolutely positioned anchor perfectly fits on top of the hot spot, just like an old school image map; except in this case the meaning of the link is clearer in a text browser or to a search engine spider than it would be just using an image maps alt attribute.

Cool stuff.

To me at least…

I might actually turn this into a WordPress plugin, by the way. I'm like 25% of the way there already. Not that we actually need another one of these things of course. I'd do it just for the pure enjoyment of creating a nice solid piece of code that can be used around the internet. If I do, I'll document the whole process here :)

Books 2008 #1 Pro JavaScript Techniques

Pro JavaScript Techniques (Pro) Reading this book I finally understand why I don't really immediately grasp JQuery code. Resig's doesn't use verbs for his function names. Instead of something like getElementsByClass(), he uses something like class(). I like verbs in my function names.

That aside, this is an excellent book for the serious JavaScript programmer. Resig does a great job of covering the breadth of modern JavaScript techniques and if you've got a reasonably solid JS foundation you can't help but come away from this book with patterns, techniques and approaches that you can apply to your day-to-day code.

Playing Around With ECMAScript for XML (e4x)

As I mentioned I was reading John Resig's Pro JavaScript Techniques recently (I actually finished it today.) The last chapter deals with the future of the language, and goes into a few different JS related technologies on the horizon- the <canvas> element, Comet, etc. One technology featured I'd never actually played around with was ECMAScript for XML (E4X.) Reading the sample code, I realized it could potentially be really useful, so I decided to take it for a little spin this afternoon, just to get a feel for what it might be like to work with. I came up with the following…

Here's some sample code:



function e4xDemo() {
      //create a new div
      var newDiv = <div/>;
      //append an H1 with some text 
      newDiv.h1 = "This is an e4x generated header";
      //give the div an ID
      newDiv.@id= "e4x";
      //append an H2 with some text
      newDiv.h2 = "let's create a more complicated structure"
      //append a whole slew of divs and a paragraph
      //this feels like it could be very powerful
      newDiv.div.div.div.div.p = "isn't this kind of cool?";
      //add another paragraph
      newDiv.p = "let's add in an image";
      //if E4X was widely supported
      //I'd use this pattern all the time
      newDiv.p.img.@src="http://media.drunkenfist.com/304/wp-content/uploads/2008/01/graffiti-letter-i.thumbnail.jpg";
      //E4X creates a variable of type XML
      //Which is basically just a string full XML
      //so we use innerHTML to jam it into the doc
      $("contents").innerHTML=newDiv;
      //Then we spit out the full text of the variable into a PRE
      $("view-source").appendChild(document.createTextNode(newDiv));
      //use the .. operator that searches all child nodes of a certain type
      $("dot-dot-p").appendChild(document.createTextNode(newDiv..p));
      return false;
  };


And here it is in action (Firefox only):

First impression? It wouldn't completely replace strings+innerHTML or the proper DOM methods like createElement or appendChild, but E4X would come in handy in a lot of situations and if it were more widely supported it would immediately get some use. For example, I'd definitely use the var newImg = img.@src = "path/to/image" pattern all the time when creating images on the fly (it's just so direct) and I'm betting I'd use <div/> and div.@id in place of some of the longer, tougher- to- read strings I drop into HTML docs with innerHTML.

I'm going to continue to experiment with it. I'm going to try to rewrite some of my existing code using E4X, so we'll see what shakes out with the tinkering.

JavaScript Dispatches From My Kilobyte Addled Brain.

I'm reading John Resig's excellent Pro JavaScript Techniques. A great book for any JavaScript programmers in the audience.

Anyway, last night I was reading the chapter on image galleries. In it, Resig, comparing Lightbox to Thickbox, writes:

"Due to the amount of extra features that ThickBox includes, along with the reduced code base, it is certainly a desirable alternative to Lightbox"

The part about the reduced code base struck me as a bit odd as Thickbox requires JQuery to function. At the time of reading I thought JQuery was about 30k packed (it turns out it's 26.5K packed,) so to my mind, Lightbox, which is a standalone script, being bigger than that seemed improbable. And that estimate didn't even factor in the Thickbox code itself.

Stranger things have happened of course, so I spent a few minutes today looking into all the pieces to flesh out the story and now I think I see what Resig was referring to- if you're already using JQuery, the Thickbox script file (11.3K unpacked/ 5.83K packed :) ) is smaller than the Lightbox script file (12.3K unpacked.)

It's especially nice that Thickbox pushes a packed version at the user, by the way.

That said, my original "huh" was justified as, if one is starting from scratch or adding a feature to an existing site that doesn't already use JQuery, then the total code cost for inserting Lightbox is considerably smaller than Thickbox (JQuery IS getting served to the browser after all.)

Of course, if you take a look at Lighbox 2, then Resig is even more right as the total cost of code on that one, written on top of Scriptaculous and Prototype, is 103K.

For what it's worth, that's nearly twice the weight of my whole home page.

What does all this mean? Nothing? Everything? Who cares? Something like that :)

Sharing is Caring- Using JavaScript to Enable Image Sharing

People hijack my images all over the web. Yes. It's true. While I'm not 100% happy about it, I'm also not 100% upset about it since I'm glad that people like my images enough to swipe them. So I tolerate it.

One thing that would make it all a lot more palatable is if people who were taking my images would link back to my site. The link would serve as credit, would drive traffic, and would increase my page rank. What's not to love?

To that end, I wrote up a little script last week that I attached to all my gallery images to maybe, just maybe, help people to do just that.

Want to try it out? Click through to view the glory of my "trouble" graffiti canvas. When you're there, right click on the image- as if you were going to "Copy Image Location."

Wasn't that cool?

For the lazybones in the audience who haven't actually clicked through, right clicking on the image triggers a little JavaScript function that throws this at the user

sharing-is-caring.jpg

As you can see it's a fairly friendly option to grab some easy-to- paste code in order to share the image. How nice am I?

If anyone actually uses it instead of just stealing the image then the whole process would be a resounding success. Traffic + page rank = good times.

Want to know how it's done? The code follows. For what it's worth, I've translated this into plain old JavaScript. There are some shortcuts that my actual code uses that I've turned back into native objects and methods so that it should be more readily grasped by folks no matter what style or library they might use in their day-to-day coding:

Anyway, on page load (either window.onload or whatever enhanced version you use- I use this ) I run this block:

if (document.body.id=="grafpg" || document.body.id=="comicspg" || document.body.id=="artpg" ) {
document.body.innerHTML+="<div id='msg'><div id='msg-body'><h3>Want to share this image?</h3><label for='grablink'>Here's the code to paste into your blog, forum post, myspace, etc :</label> <textarea name='textarea' id='grablink'></textarea><p id='download'></p><p>All images &copy; Rob Larsen</p></div><div id='clear-msg'></div></div><div id='cloak'></div>";
createShareLinks();
}

In my specific case I know that pages with ids of grafpg, comicspg and artpg are the page types that will have gallery images I want to manipulate. If any of those three page IDs show up, I use innerHTML to append the basic structure of the overlay to the page. As a note, because I have this structure already in place, this script is completely unobtrusive. I didn't need to change the HTML at all to implement this functionality. Such is the benefit of thinking a little bit about the semantic meaning of ID and CLASS attributes. Since went so far as to separate the three "types" of art page, even though they display exactly the same, I could conceivably present three separate versions of the interface depending on the site section, still without touching the underlying HTML. Structure is cool.

I should mention I love this sledgehammer approach to appending content to a page. I admit it wholeheartedly. It's just so damned direct I can't help but smile. Don't get me wrong, I love createElement, appendChild, etc. and use them all the time. It's just, being an HTML guy at heart I love to be able to mock up a display like this and then just drop it into a page with very little fuss. HTML source to JavaScript flashiness in no time flat :)

Anyway, after appending the overlay divs, I initiate the guts of the behavior with the createShareLinks() function. The source of which follows:

function createShareLinks(){
// there can be more than one img on a gallery page. Get the full nodeList of images
   var theImg = document.getElementById("artimg").getElementsByTagName("img");
// and loop through
   for ( var i=0;i<theImg.length;i++ ){
// attach an event to the contextmenu event
// did you know there was such a thing?
      theImg[i].oncontextmenu = function() {
// do come calculations to create the proper
// height and width for the cloak and msg divs;
         document.getElementById("cloak").style.width = document.getElementById("msg").style.width = this.offsetWidth  + 2 + "px";
         document.getElementById("cloak").style.height = document.getElementById("msg").style.height = this.offsetHeight + 2 + "px";
// there's some padding we need to take into account
         document.getElementById("msg-body").style.height = this.offsetHeight - 32  + "px";
// get the x and y of the image and set the
// top and left of the divs accordingly
         document.getElementById("cloak").style.left = document.getElementById("msg").style.left = (findX(this) -1) +"px";
         document.getElementById("cloak").style.top =  document.getElementById("msg").style.top =  (findY(this) - 1) +"px";
// build the link text.
         document.getElementById("grablink").value="<a href='http://www.drunkenfist.com/'><img src='"+this.src+"'  alt='image copyright rob larsen' /></a>";
// I just like this
         document.getElementById("grablink").onfocus = function() {
            this.select();
         };
         document.getElementById("download").innerHTML="<a href='"+this.src+"'>Download this file</a>";
         document.getElementById("clear-msg").onclick= clearShareLinks;
// show the divs
         document.getElementById("cloak").style.display = document.getElementById("msg").style.display = "block";
         return false;
      }
   }
};
//a simple function to hide the overlay;
function clearShareLinks() {
   document.getElementById("cloak").style.display = document.getElementById("msg").style.display = "none";
}

First I create a nodeList of all images contained in div id="artimg." Once I have that nodeList, which will contain either one or two nodes, I loop through and attach an oncontextmenu event handler to the image. Did you know there was an oncontextmenu event handler before reading this article? If not, now you do :) In the function that fires when a user right clicks (or control clicks) on an image I do some basic dHTML goodness. First I set the height and width of the two divs to equal the height and width of the target image and then I use the target image to calculate the left and top of the divs so that they sit right on top of the image. Once that's all set I do some string manipulations to build out the link, some random other housekeeping and then I flip the switch and show the divs to the world in all of their glory.

By the way- are you thinking… "why two divs?"

Well, the one div, the one you'd expect to be the parent, I want to be semi-opaque in order to cloak the image. Thing is, one of the properties of CSS opacity is that all child elements inherit the parent's opacity. Meaning I couldn't have 100% opaque text inside a DIV with 80% opacity. Which would suck since it would be tougher to read. Instead, I fake it with two DIVs styled to act as one. Fun times.

Want to see the CSS?

Here it is:

#msg, #cloak {
  position:absolute;
  width:0;
  height:0;
  left:0;
  top:0;
  display:none;
}
#cloak {
  opacity: .50;
/* IE, if you need this to validate, move into a separate IE sheet */
/* and hide from other browsers/ the validator with conditional comments */
  filter:Alpha(opacity=50);
  z-index:9998;
  background-color: #0099FF;
}
#msg {
  z-index:9999;
}
#msg-body {
  width:75%;
  margin:auto;
  padding-top:35px;
}
#msg-body h3 {
  background: #ddd;
  padding:5px;
  width:100%;
  color:#000;
  border:1px solid #000;
  border-bottom:3px solid #000;
  border-right:3px solid #000;
}
#msg-body p {
  width:100%;
  background: #ddd;
  padding:5px;
  border:1px solid #000;
  border-bottom:3px solid #000;
  border-right:3px solid #000;
}
#msg-body label {
  font-size:.82em;
  font-weight:bold
  display:block;
  padding:5px;
  background: #ddd;
  width:100%;
  margin-bottom:10px;
  border:1px solid #000;
  border-bottom:3px solid #000;
  border-right:3px solid #000;
}
#grablink {
  width:100%;
  height:100px;
  background:#efefef;
  border:1px solid #000;
  border-bottom:3px solid #000;
  border-right:3px solid #000;
  overflow:hidden;
  font-size:10pt;
  padding:4px;
}
#clear-msg {
  position:absolute;
  right:5px;
  top:5px;
  width:30px;
  height:30px;
/* sprites are my friend */
  background: url(http://media.drunkenfist.com/img/sprite.1.png) -597px -185px no-repeat;
/* make it look clickable */
  cursor:pointer;
  cursor:hand
}

And that's that. Will it get used? I hope so. If not, it's the thought that counts, right?

I just realized- JavaScript is my Perl

Twice this morning I did massive, repetitive, string manipulations with JavaScript.

One took a list of files, turned it into an array and then looped through creating .htaccess entries.

The other took an HTML table output by Excel and turned it into a Definition List. I then used FireBug to copy the innerHTML of the body and pasted it into a new document, ready to be manipulated in the application I'm building (with JavaScript of course :) ) If you're curious, here's the code for that one:

<script type="text/javascript">
window.onload = function() {
    var trs = document.getElementsByTagName("TR");
    var newString ="<dl>";

    for (i=0;i<trs.length;i++){
        var tds=trs[i].getElementsByTagName("TD");
        newString +="<dt id='"+tds[1].innerHTML+"'>"+tds[4].innerHTML+"</dt>";
        newString +="<dd>"+tds[5].innerHTML+"</dd>";
    }
    newString +="</dl>"
    document.body.innerHTML=newString;
    }
</script>

Anyway, I've done this sort of thing before and I realized that I'm using JavaScript for the sort of administrative scripting that other people would use Perl or Python for.

No, there's nothing more to this post than that.

:)

I just wanted to point it out since it struck me as interesting.

Does anyone else out there use JS for this sort of thing?

Or am I a complete weirdo?