Paul Irish

Making the www great

Random Hex Color Code Generator in JavaScript

For fun I asked a few friends for ideas on a random color generator in a single line of javascript. You know, these guys: #0afec0, #c9f2d0, #9b923e.

Here’s what we came up in about two minutes (in chronological order)…

1
2
3
'#' + (function co(lor){   return (lor +=
  [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'][Math.floor(Math.random()*16)])
  && (lor.length == 6) ?  lor : co(lor); })('');

Similar recursive technique, but using a string instead of an array and aliasing the Math object:

1
2
(function(m,s,c){return (c ? arguments.callee(m,s,c-1) : '#') +
  s[m.floor(m.random() * s.length)]})(Math,'0123456789ABCDEF',5)

Using a named function expression instead of arguments.callee.

1
2
'#'+(function lol(m,s,c){return s[m.floor(m.random() * s.length)] +
  (c && lol(m,s,c-1));})(Math,'0123456789ABCDEF',4)

If we assume JavaScript 1.6, then we could just use Array.map():

1
2
'#'+'0123456789abcdef'.split('').map(function(v,i,a){
  return i>5 ? null : a[Math.floor(Math.random()*16)] }).join('');

But then, the magic of Math struck (16777215 == ffffff in decimal):

1
'#'+Math.floor(Math.random()*16777215).toString(16);
Thx to ben alman, nlogax, and temp01 for their smarts.

Log() - a Lightweight Wrapper for console.log

There are a few things that a console.log wrapper can and should do:

  • Prevent errors if a console isn’t around (i.e. IE)
  • Maintain a history of logs, so you can look in the past if your console is added afterwards (e.g. firebug lite)
  • Normalize the browser differences in console integration (e.g. when passing multiple arguments into console.log())
  • For something you type regularly, make it quicker to type for the lazy among us.

But there are a few considerations…

Console.log.apply doesn’t handle multiple arguments in Safari 3 or Chrome 1.1

Firebug, Chrome, and Safari have a clearer presentation for strings when inside an array:

More details on how firebug and webkit inspector visually view these things here: http://gist.github.com/466188

Extra features

  • A reverse-chronological history, accessible as an array at log.history
  • I have also included (I removed it) a shorthand logargs() function that is useful when you’re inside a function and want to know the context and arguments passed in. I use it a lot in ajax callbacks. Worth noting that it uses arguments.callee.caller, which will be deprecated in ECMAScript 5 Strict mode. :( I killed off logargs cuz nobody lurved it like I did. If you want it… pastie.org/1033665

The code:

1
2
3
4
5
6
7
8
9
// usage: log('inside coolFunc',this,arguments);
// http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
window.log = function(){
  log.history = log.history || [];   // store logs to an array for reference
  log.history.push(arguments);
  if(this.console){
    console.log( Array.prototype.slice.call(arguments) );
  }
};

And if you’d like it minified:

1
window.log=function(){log.history=log.history||[];log.history.push(arguments);if(this.console){console.log(Array.prototype.slice.call(arguments))}};

Interestingly, the minified version of this script is smaller (262 148 bytes), and arguably more useful, than the minified firebugx.js, which I’ve covered before. Plus it has one more feature.

Plus Firebug lite?

You got it. This bookmarklet will add firebug lite, and then output the logged history when it’s ready:

>>> Fbug Lite+log <<<

Want more power?

After writing this, I worked with Ben Alman on a more comprehensive and robust logging script. It’s excellent if you take full advantage of the console API. And you should be aware that Safari 4 and Chrome 2 have most of that API supported. Make full use of it and don’t you dare type another alert()!
2010.05.20: Updated log code. Fixed some edge case bugs.

2010.07.06: Updated code again. removed logargs. link to pretty viewings in the gist

2011.04.12: Craig Patik expanded the functionality of this in a lot of detail. Great post!

jQuery idleTimer Plugin

There are a few cases where you want to know if the user is idle. Namely:

  • You want to preload more assets
  • You want to grab their attention to pull them back
  • You want close their banking session after 5 minutes of inactivity. (Jerk!)
  • You want the site to sneak off the screen and see if they notice ;-)

Nick Zakas wrote a script for YUI3 to handle these cases. His writeup has a great description of the architecture approach he took to the script.

In my jQuery adaptation, I did a few different things:

  1. Leveraged event namespaces for easy unbinding
  2. Considered mousewheel as activity, in addition to keyboard and mouse movement.
  3. Gave it a bit more jQuery-ish of an API

To use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// idleTimer() takes an optional argument that defines the idle timeout
// timeout is in milliseconds; defaults to 30000
$.idleTimer(10000);


$(document).bind("idle.idleTimer", function(){
 // function you want to fire when the user goes idle
});


$(document).bind("active.idleTimer", function(){
 // function you want to fire when the user becomes active again
});

// pass the string 'destroy' to stop the timer
$.idleTimer('destroy');

Get the source on github (4.6k unminified) View the demo

Note: If you want to change the timeout interval, you’ll have to destroy the existing timer first.

2009.09.22: I’ve updated the idleTimer script for a few more features…
1
2
3
4
5
// you can query if the user is idle or not with data()
$.data(document,'idleTimer');  // 'idle'  or 'active'

// you can get time elapsed since user when idle/active
$.idleTimer('getElapsedTime'); // time since state change in ms

You can get the latest code, naturally, on github.

2010.05.11: Due to popular demand, there is now support for multiple timers!!

Why would you want this? Lets say you want ..

  • One Timer to restore the forms, messages boxes, etc.
  • Another Timer of a different length timeout to notify about expiration sessions.
1
2
3
4
5
6
// bind to specific elements, allows for multiple timer instances
$(elem).idleTimer(30*1000);
$(elem).idleTimer('destroy');
$(elem).idleTimer('getElapsedTime'); // some ms something

$.data(elem,'idleTimer');  // 'idle'  or 'active'

Notice this new API is on $.fn.idleTimer, as in it works on a jQuery collection instead of just the jQuery global object.

If you’re using this along with the old $.idleTimer api, you should not do $(document).idleTimer(...)

All these element-bound timers will only watch for events inside of them. You may just want to watch page-level activity, in which case you may set up your timers on document, document.documentElement, and document.body. Those will allow three separate timers that will catch all page activity.

Again, check out the demo or view the source on github. :)

2011.03.11 : You should check out Eric Hynds’ Idle Timeout plugin. It improves a good bit on this guy here.