JavaScript Countdown Timer

I was in search of a JavaScript countdown timer (mainly because I’m too lazy to build it out myself — and because I’m sure millions before me have done the same), but Google wasn’t doing me much good. Most scripts would modify the DOM, directly but not make it easy to programmatically intercept the remaining time.

So, I picked one of the cleanest scripts and cleaned it up a bit.


/**
 * A sweet js countdown timer with a custom callback that gives you a JSON object!
 * Heavily modified code originally found on http://www.ricocheting.com/code/javascript/html-generator/countdown-timer
 *
 * @param string|Date String representation of when to countdown to. Date objects probably work too
 * @param callback Function triggered when the interval has passed
 * @param int Number of milliseconds for the timeout. Defaults to 1000 (1 second)
 *
 * @return object Returns a JSON object with properties: days, hours, minutes, seconds
 */
timer = function(endDate, callback, interval) {
    endDate = new Date(endDate);
    interval = interval || 1000;

    var currentDate = new Date()
        , millisecondDiff = endDate.getTime() - currentDate.getTime() // get difference in milliseconds
        , timeRemaining = {
            days: 0
            , hours: 0
            , minutes: 0
            , seconds: 0
        }
        ;

    if(millisecondDiff > 0) {
        millisecondDiff = Math.floor( millisecondDiff/1000 ); // kill the "milliseconds" so just secs

		timeRemaining.days = Math.floor( millisecondDiff/86400 ); // days
		millisecondDiff = millisecondDiff % 86400;

		timeRemaining.hours = Math.floor( millisecondDiff/3600 ); // hours
		millisecondDiff = millisecondDiff % 3600;

		timeRemaining.minutes = Math.floor( millisecondDiff/60 ); // minutes
		millisecondDiff = millisecondDiff % 60;

		timeRemaining.seconds = Math.floor(millisecondDiff); // seconds

        setTimeout(function() {
            timer(endDate, callback);
        }, interval);
    }
    
    callback(timeRemaining);
}

It’s easy to use! You specify an end date (as a string, though Date object’s should work as well) and pass in a callback that gets triggered at a set interval. The callback receives a JSON object with properties for days, hours, minutes and seconds. You can pass in a custom interval if you want the callback triggered at a different period. Examples below.


timer('2011-12-31', function(timeRemaining) {
	console.log('Timer 1:', timeRemaining);
});

// This will run every minute, instead of every second
timer('2012-12-31', function(timeRemaining) {
	console.log('Timer 2:', timeRemaining);
}, 60000);

Interested? See it in action: http://jsfiddle.net/mjangda/vGv7J/1/

[[Prototype]] vs prototype (Peter van der Zee on JSMentors)

Here’s a great explanation (by Peter van der Zee) of the key differences between [[Prototype]] and prototype in JavaScript. It finally makes sense now!

Note: to understand this explanation it would help to know what prototype is/does and how it works.

So we have [[Prototype]] and prototype. You can see prototype as the parent object to which [[Prototype]] (so __proto__) refers to on instances of the constructor. Hah, I’m sure that’s not confusing. So let me give an example :)

var A = function(){};
var a = new A();
log(a instanceof A); // true
log(A.prototype); // object
log(a.prototype); // undefined
log(a.__proto__); // object, in browsers that support the mapping
log(a.__proto__=== A.prototype); // true.

“A” has a prototype property (A.prototype). If you add new properties to that object, they will automagically be available on “a”. “a” has a [[Prototype]] internal property. It refers to A.prototype. It is an essential part of the prototypal chain because it actually determines the next part of the chain. If you change a.[[Prototype]], changes to A.prototype will no longer be reflected on “a”. In fact, all not “own” properties of a will no longer be accessible and are replaced by a new set of properties.

via [JSMentors] Object creation.

WordPress Tip: Hooking into Widget Save Callback

John Gadbois turned some code I gave him into short and useful write-up on how to hook into AJAX calls triggered when saving widgets. It makes use of jQuery’s Global AJAX event handlers, which allow for some very cool things, especially when you’re working with external libraries that use the jQuery AJAX methods. A future blog post will cover how plugins can use the ajaxSend event to hook into WordPress’ autosave.

jQuery Plugin: HTML5 Inline Data

HTML5 Data Attributes are sexy.

What’s sexier is an easy way to work with these data attributes using jQuery.

Sure, you could do something like:

jQuery('#pancakes').attr('data-type');

But who wants to type the “data-“ prefix over and over again?

So, here’s a quick little plugin I whipped up. It’s probably terrible when it comes to jQuery plugin standards (I do WordPress plugins, not jQuery), but it works. It works as a getter and setter.

Bonus: If you’re using jQuery 1.4.1+, the plugin supports well-formed JSON objects as data attribute values.


/*
* Inline Data - get and set HTML5 data attributes! Yay!
*
* Copyright (c) 2010 Mohammad Jangda (http://digitalize.ca), Vortex Mobile (http://www.vortexmobile.ca)
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
*/

(function($) {
    $.fn.inlinedata = function(name, value) {
        
        var prefix = 'data-';
        var attr = prefix + name;
        var values = []
        
        this.each(function(i) {
            var attrValue;
            
            // Setting values
            if(value) {
                // If an array is passed, the array index should correspond to the collection index
                if($.isArray(value)) {
                    // Check, check, check the index. Because out of bounds exceptions are the devil!
                    if(typeof(value[i]) !== 'undefined')
                        attrValue = value[i];
                    else
                        attrValue = '';
                } else {
                    // Not an array, so we're just giving all the elements the same value
                    attrValue = value;
                }
                this.setAttribute(attr, attrValue);
            } else {
                // Getting values
                attrValue = this.getAttribute(attr);
                
                try {
                    // try parsing as JSON
                    attrValue = jQuery.parseJSON(attrValue);
                } catch(e) { }
            }
            attrValue = (attrValue) ? attrValue : '';
            values.push(attrValue);
        });
        
        if(values.length == 1)
            return values[0]
        
        return values;
    }
})(jQuery);

Usage is simple:














JavaScript Tip: Save me from console.log errors

It’s bound to happen. You build yourself a sweet webapp with some sweet javascript action and you unleash it to the world only to get angry emails yelling, “IT DOESn’T WoRK! FIX iT okAy?” And it’s the darndest problem because it’s happening to both IE and Firefox users (Chrome and Safari users have been silent) and you can’t replicate it.

And then you spend hours trying to figure out the problem to no avail, leaving you scratching that magnificent head of yours with luscious, flowing hair. You just can’t replicate the problem. But then, after hours and days of staring intently at the screen, you find it. It’s a rogue console.log call that you forgot to comment out. And then you spend the remainder of the week chastising yourself for being stupid.

It happens. (To be fair, it’s not your fault that your users don’t have Firebug or IE Developer Tools installed. Blame it on Mozilla/Microsoft.)

But there’s an easy solution. Just copy the following javascript somewhere in your project, and rest easy:


if(typeof(console) === 'undefined') {
    var console = {}
    console.log = console.error = console.info = console.debug = console.warn = console.trace = console.dir = console.dirxml = console.group = console.groupEnd = console.time = console.timeEnd = console.assert = console.profile = function() {};
}

jQTouch: Tap vs Click

jQTouch has a sweet feature which adds a fast touch or “tap” event. It’s pointless for me to try and rephrase, so learn all about it on the jQTouch blog: Milliseconds Responsiveness and the Fast Tap

Now, the only downside to the tap event, is that it doesn’t work on anything other than Mobile Safari. So for iPhones, you can use tap event, but non-iPhones, you have to use click event. You could just make things easy on yourself and use clicks across the board, but I can tell you that the tap event immensely increases the performance and responsivity for jQTouch apps on iPhones. Good news is, there’s an easy way to work with both.

The code below was inspired by Samuel’s message on the jQTouch Google Group.

<script type="text/javascript">
var userAgent = navigator.userAgent.toLowerCase();
var isiPhone = (userAgent.indexOf('iphone') != -1 || userAgent.indexOf('ipod') != -1) ? true : false;
clickEvent = isiPhone ? 'tap' : 'click';
</script>

You can now easily bind your events as follows:

<a href="#link" id="mylink">Click or Tap me!</a>
<script type="text/javascript">
$('#mylink').bind(clickEvent, function() {
    e.preventDefault();
    alert('Yay! You just ' + clickEvent + 'ed me!');
});
</script>

Note: in my testing, the tap event doesn’t register too well on the iPod Touch. If that seems to be the case, I’d recommend defaulting iPod Touches to use clicks instead. However, since the iPod Touch user agent includes the term “iPhone”, we have to un-include it from our tap list:

<script type="text/javascript">
var userAgent = navigator.userAgent.toLowerCase();
var isiPhone = (userAgent.indexOf('iphone') != -1) ? true : false;
if(userAgent.indexOf('ipod') != -1) isiPhone = false; // turn off taps for iPod Touches
clickEvent = isiPhone ? 'tap' : 'click';
</script>

jQuery tip: Visually separating DOM elements in code

Here’s a quick tip I picked up from Chris Coyier (the genius behind CSS-Tricks and Digging Into WordPress).

To help keep variables that contain DOM elements visually distinct from other regular variables, just prepend a $ (dollar sign) to them. Example:

<script type="text/javascript">
// assign the variable
var $div = jQuery('#myDiv');
// Do stuff to it
$div.animate({width: '200%'}, 1500);
</script>

This way, you can easily pick out which variables contain DOM elements when viewing code, without resorting to excessive naming conventions (such as divContainer or divDomObject, etc.). Your code stays clean, lean, and easy to read.

Rock on.