Coding with Jesse

Do It Now

Talk about synchronicities. The day after I linked to some motivation quotes, my favourite blogger, Steve Pavlina, puts up a new article entitled Do It Now. It's 8000 words, so if you have some time now give it a read, or you might want to bookmark it for later. Steve's writing is a pleasure to read, and he written many great points on personal motivation and productivity in the past that he has seemed to incorporate into this article.

It's also worth mentioning that Steve has recently managed to change his sleeping habits and become a polyphasic sleeper. This means he sleeps for 25 minutes every 4 hours (a total of less than 3 hours a day!) If you're at all interested in this, go check out his journal logs and the rest of his website.

[Update: The synchronicities didn't stop there. I just noticed that on Success Begins Today, John updated his earlier motivation post with a followup entitled Success: Just Do It. It must be Determination Week!]

Published on November 29th, 2005. © Jesse Skinner

Hide Firefox Referals From Firefox Users

I'm glad Julian Bez pointed out we don't have to bother Firefox users with Adsense Firefox referals. Just yesterday, Google opened up Firefox referals for International content providers. I immediately added the banner to the Tools page of this site, and to Free Horoscope Daily, but I totally didn't think about showing Firefox users something different. Julian also outlines how to accomplish this easily with PHP. Thanks, Julian.

Published on November 29th, 2005. © Jesse Skinner

Motivation is a Trap

Over on Success Begins Today, John Richardson put up some great Quotations by John Maxwell:

"The whole idea of motivation is a trap. Forget motivation. Just do it. Exercise, lose weight, test your blood sugar, or whatever. Do it without motivation. And then, guess what? After you start doing the thing, that’s when the motivation comes and makes it easy for you to keep on doing it."

"As you begin changing your thinking, start immediately to change your behavior. Begin to act the part of the person you would like to become. Take action on your behavior. Too many people want to feel, then take action. This never works."

This reminds me a lot of the time I was going to university. I'd spend hours searching and reading articles on the Internet about beating procrastination. I was spending so much time trying to figure out how to get the motivation to do the things I wanted to do.

Eventually, I realised the only way to Get Things Done was to just do them! I don't know what other solution I thought I would find.

Nowadays, I love reading all the tips and tricks for Getting Things Done. It seems like everyone is obsessed with productivity and anti-procrastination. But I also worry that people are spending all their time configuring their Hipster PDA or organising emails in Outlook instead of just working on the things that need to get done.

Now, before you cry "Blasphemy!", I think the principals of Getting Things Done are really great. More or less, I've been applying them for many years. Basically, I keep a file, todo.txt, with everything I need to get done. I have one at home and one at work. I separate it into sections like so:

Main Project
============

sub project
- thing to do
    - detail on that thing
        - sub detail
    - another detail
- another thing to do

And if I ever forget what my Next Action is, I just take a look in the file. But I don't feel I need to do a lot of the other things, like reviewing, or some kind of inbox. I guess I'm just not as busy as some people, I usually have a good idea of all the things I have to do without it causing me stress.

Anyway, these quotes make a great point: finding ways to motivate yourself is a waste of time. If you're going to do anything, go do the thing you need to do.

Published on November 28th, 2005. © Jesse Skinner

No-JavaScript CSS

On one of my web sites, I use JavaScript to show/hide div layers containing each section. I have links to "#section-five" for example, but the onclick event changes the section-five div to display: block; and the previous div to display: none;. This is designed so that browsers without CSS or JavaScript will still be able to use the links as regular anchor links. This assumes, though, that the visitor would either have both CSS and JavaScript, or neither.

Since I wrote this, I've been struggling with how to deal with visitors who have CSS but not JavaScript. Today I figured out a way to do this.

The typical solution would be to have display: block; set by default, then to use JavaScript to set display: none; onload. I tried this solution, but I didn't like how all the layers appeared at first, then suddenly disappear. I wanted a solution that wouldn't affect the experience for most users.

All I needed to do was display different CSS to users without JavaScript. To accomplish this, I first considered setting disabled on the style sheet, then using JavaScript to enable the CSS link. This didn't work right in Firefox because Firefox ignores the disabled attribute of link tags.

Next, I tried setting the href on the link tag to href="", then dynamically setting the href using JavaScript. This worked good, except then users without JavaScript would be forced to see the page without CSS. It was perfectly usable but looked pretty boring.

Finally, I came up with this compromise. The link tag on the page is:

<link rel="stylesheet" type="text/css" media="screen"
 href="nojavascript.css" id="stylesheet"/>

so by default, visitors will get a "nojavascript.css" CSS file. This file contains:

@import "screen.css";
div.section { display: block; }
#ads { display: none; }

So without JavaScript, the page has all the div layers displayed, except the ads. (Adsense and Chitika won't work without JavaScript anyway.) Also, by using an @import, I won't have to maintain two almost-identical CSS files.

Next, I added a line to the JavaScript file attached to the page:

document.getElementById('stylesheet').href = "screen.css";

Note that I didn't put it in an onload function. I don't want the page to change once it's been loaded; I want it to look right from the start. If you do this, you'll have to make sure that the <script> tag comes after the <link> tag.

The other nice thing about this method: it ensures that users with browsers that doesn't support getElementById will still get the nojavascript.css file. This is important because it is the only method I use for handling the onclicks.

That's it. Simple, yet powerful.

Published on November 28th, 2005. © Jesse Skinner

Web Content Accessibility Guidelines 2.0

As announced yesterday in the W3C News:

The Web Content Accessibility Guidelines (WCAG) Working Group has released Working Drafts of the Web Content Accessibility Guidelines 2.0 and HTML Techniques for WCAG 2.0 and a First Public Working Draft of Understanding WCAG 2.0.

Unlike many W3C documents, these are actually quite readable and useable right away. They make some great points, some of which surprised me a bit. Web accessibility is often reduced to screen-reader functionality. This document goes quite a bit outside that narrow view and ensures that the web is fully accessible to users with a wide range of disabilities. These includes learning difficulties, cognitive limitations, speech difficulties and others.

As a result, following the advice in these documents seems like it would enhance the usability of the web for all users, even those without disabilities. Here are some of the more interesting points I noticed in these documents.

  • Guideline 2.5 - Help users avoid mistakes and make it easy to correct them. This is really great, general advice. It suggests validating input, providing context-sensitive help, and offering users a chance to review or possibly undo actions.
  • Guideline 3.1 - Make text content readable and understandable. Again, very useful and general advice that improves usability for all users. It suggests avoiding the use of jargon or words used in an unusual way. Also, the use of simple language summaries or diagrams to explain complex concepts to users with reading ability less advanced than "lower secondary education".
  • H46: Using null alternative text and no title attribute on img elements for spacer or purely decorative images. This makes perfect sense once I read it, but I had never given much thought to this being a real problem. I always thought about empty alt and title tags as a kind of work around. However, putting things like "side" or "blue bar" in alt tags on pure display images would just be annoying and unneccessary to a user with a screen reader.

If you haven't yet, I suggest giving these documents (at least the guidelines and techniques) a quick read. It's good to be reminded now and then of the simple ways we can make the web accessible and usable to everyone.

Published on November 24th, 2005. © Jesse Skinner

CloneCD For Mac OS X

If you find yourself with a Clone CD set of files (.CCD, .CUE, .IMG & .SUB), and you're using OSX, you'll probably realise quickly that you can't burn these files. This is because CloneCD is unfortunately only available for Windows.

Luckily, there is still a way around this. Here's the steps I had to follow:

  1. Download Firestarter FX. You can also use any program that can burn .BIN/.CUE files
  2. Install Firestarter. For me, this wasn't so straightforward. StuffIt crashed when I tried to open the ZIP file, so I had to unzip it from the command line. If the ZIP file is on the Desktop, just open Terminal and type "cd Desktop" and then "unzip FireStarter*.zip". This created a folder on the desktop containing the program.
  3. Rename your .IMG file to .BIN. This is the hack: CloneCD .IMG files are really normal .BIN files in disguise. It's just the file extension that confuses cd burning programs. By renaming, Firestarter will be able to open it.
  4. Open Firestarter, drag the .BIN and .CUE files onto the Firestarter window, and burn.

That's it! Now you should have a perfect burnt CD without having to copy the files over to a Windows computer!

Published on November 22nd, 2005. © Jesse Skinner

Feedburner RSS

I have started using Feedburner for The Future Of The Web's RSS feed. If you have already subscribed to the old RSS feed, I highly recommend you change your RSS reader to point to:

http://feeds.feedburner.com/tfotw

If you have no idea what I'm talking about, or if you haven't yet subscribed to the RSS feed of this page, you should definitely check out an RSS feed aggregator. I use Bloglines. It's exactly what I need. It lets me see what's I've read or haven't read across the 30 or so web sites I like to read, and it's a very nice interface that stays out of my way. There are dozens of other ways to subscribe to RSS feeds, so there is definitely one out there that would be perfect for you.

Published on November 18th, 2005. © Jesse Skinner

Chitika Channel Tips

I started using Chitika eMiniMalls a few days ago on Free Horoscope Daily, as well as on the tools pages of this site. So far so good, it seems like a very promising ad service. The ads can be contextual like Google Adsense, but I suspect you can get them to perform better by specifying keywords to bring up the product you want.

Very recently, Chitika added a JavaScript variable to allow for Channels, ch_sid. Instead of having a Channel management area on the website, where you set up channels and get a numeric ID to use for the channel, they allow you to specify any string at all. This makes testing out different ad styles and keywords very easy.

To test out keywords, that is, to see which keywords bring up products people are actually buying, we can create the Channel name dynamically using Javascript:

ch_queries = new Array("ipod", "camera", "dvd player", "etc.");
ch_query = ch_queries[Math.floor((Math.random()*ch_queries.length))];
ch_sid = 'Channel Prefix ' + ch_query;

This will give you channel names like "Channel Prefix camera" or "Channel Prefix ipod", etc. Of course, you can change Channel Prefix to include more information on the type of ad or location of the ad.

You could also experiment with different ad colors or sizes in a similar way, and build up the ch_sid variable to include all the variables. For example:

ch_colors = new Array("red", "blue", "green");
ch_color = ch_colors[Math.floor((Math.random()*ch_queries.length))];
ch_sid = 'My Website ' + ch_color + ' ' + ch_query;

You get the picture. Of course you can do all this with Adsense too, you would just have to set up a channel manually for every color / size / location combination, then dynamically associate the combination with it's channel ID. Quite a bit more painful though.

Chitika also allows you to test out searches on their website. They actually recommend you go to Amazon or Shopping.com and find best selling products, then try to create keywords that bring up that specific product. And with this Javascript, you can determine what the best selling products really are for your visitors.

Have fun optimizing your ads!

Get Chitika eMiniMalls
Published on November 11st, 2005. © Jesse Skinner

onAfterPaste

Working with designMode="on" or contentEditable (what can we call this? I want to say Rich Text Editors or Midas Editors Web-Based HTML Editors or something. We don't really have a nice buzzword for this..), a common problem is dealing with pasted content. The user can paste any HTML into these areas, and more often than not, web applications don't want form elements or IFrames or other HTML included in the content.

It's not so difficult to process the innerHTML of a document to strip out bad HTML using regular expressions. The problem is, when can this cleaning happen?

Mozilla has no paste events at all. Internet Explorer has onBeforePaste and onPaste events, but no onAfterPaste. onPaste fires when the user pastes, but before the HTML actually goes into the editor. The idea is that the developer has a chance to look into the clipboard using window.clipboardData.getData(). Unfortunately, you can only retrieve the contents in URL or Text format, not HTML. Instead, it would be easier to allow the HTML to be pasted, then process the editor contents afterwards.

To accomplish this in Internet Explorer, we can simply set a timeout in the onPaste event. This works by allowing the browser time to finish its internal onPaste event before executing the code in the timeout. The onPaste event needs to be attached to the BODY of the editor IFrame using designMode, or the DIV element when using contentEditable.

function onPasteHandler(e) {
     setTimeout(function() {
          // editor cleaning code goes here
     }, 1); // 1ms should be enough
}

In Firefox, we can't use paste events. However, probably the best we can do is set a keypress handler and look for CTRL+V or SHIFT+INSERT and then do the same thing with a timeout. The keypress event handler needs to be attached to the document element in the IFrame.

function onKeyPressHandler(e) {
     if ((e.ctrlKey && e.keyCode == e.DOM_VK_V)
      || (e.shiftKey && e.keyCode == e.DOM_VK_INSERT)) {
          setTimeout(function() {
               // editor cleaning code goes here
          }, 1);
     }
}

This should only work with Mozilla/Firefox because e.DOM_VK_V and e.DOM_VK_INSERT are not defined in Internet Explorer.

Also note that there are still other ways to get HTML into the editor through Drag-and-Drop, or by using Edit>Paste on the Firefox menu. If you are serious about stripping HTML you will need to do it at other times as well. At least this way it will happen quickly enough that the editor won't misleadingly contain these elements, only to strip them out at an unpredictable time in the future.

Published on November 10th, 2005. © Jesse Skinner

New Tools

Just for fun, I added a few simple JavaScript powered conversion tools, and PHP powered "geek" tools. There are just a few, but I will probably add more in the future. I don't know if they will be of use to anyone (except me perhaps), but feel free to steal the JavaScript for your own purposes.

Published on November 6th, 2005. © Jesse Skinner