Archive for December, 2012

The bilirubin graph uses jQuery UI and used to use the official theme switching widget, which I just discovered has been broken since September 2012. That's the problem with graceful degradation; when something breaks the page still works so smoothly I don't notice unless I'm paying close attention. Anyway, David Hoff has written a replacement, Super Theme Switcher which works well, but requires an explicit option to tell the plugin where to find the sample images:

$('#themeswitcher').themeswitcher({
	imgpath: '/inc/themeswitcher/images/'
});

The other thing I needed was a way to detect the change in theme. themeswitcher has an onSelect callback, but that is called when the new stylesheet is added to the page, not when it is actually loaded. I previously used a hack with fake images. But that was a terrible hack. Chrome still doesn't trigger load events for stylesheets, so that won't work. But all the modern browsers support CSS transitions, including the transitionend event (webkit requires a prefix).

So to detect a change in stylesheet that affects, say, elements with a class of ui-state-default, do the following:

var div = $('<div class=ui-state-default>').css({
  transition: 'color 0.01s',
  webkitTransition: 'color 0.01s',
  visibility: 'hidden' // make sure the element is invisible
}).appendTo('body').on('transitionend webkitTransitionEnd', function(){
  alert $(this).css('color'); // or whatever
});

Internet Explorer, of course, doesn't support CSS transitions (we'll see about IE 10), but luckily they are the only ones to correctly support stylesheet load events and we can use $('link:last').one('load', function(){ whatever });. So we can detect stylesheet loading in either case, and create a new version of themeswitcher that calls the onSelect callback when the stylesheet is loaded, not when it is added:

// create the test div
var div = $('<div class=ui-state-default>').css({
	transition: 'color 0.01s',
	webkitTransition: 'color 0.01s',
	visibility: 'hidden'
}).appendTo('body');

 // decide if we can handle CSS transitions
$.support.transition =
 document.body.style.transition !== undefined ||
 document.body.style.webkitTransition !== undefined;

$.fn.themeswitcher2 = function(opts){
	if (opts.onSelect && $.support.transition){
		div.on('transitionend webkitTransitionEnd', opts.onSelect);
		delete opts.onSelect;
	}else if (opts.onSelect){
		// this is really browser sniffing; it turns out that the only major browser that doesn't support transitions is IE, and they support
		// the stylesheet onload event
		// We know that themeswitcher adds the last stylesheet, so tie into that load event
		var onSelect = opts.onSelect;
		opts.onSelect = function(){
			$('link:last').one('load', onSelect);
		};
	}
	return this.themeswitcher(opts);
};

And this works in Chrome, Firefox, Opera and IE. See it in action on the bilirubin graph.

I was playing with a minor project and wanted to simulate a command line interface, like the old April Fools xkcd, and realized that their code was far more complicated than what you need if you use jQuery and contenteditable.

My quick jQuery plugin to turn any <div> into a terminal emulator is:

	$.fn.cli = function(handler, prompt, effect){
		if (!prompt) prompt = '&gt;&nbsp;';
		if (!effect) effect = $.fn.text;
		return this.each(function(){
			var self = $(this);
			function newline(){
				self.
				 append('<p class=input><span class=prompt>'+prompt+'</span><span  style=outline:none contenteditable></span>').
				 find('[contenteditable]')[0].focus(); // focus only works on the element, not the jQuery object
			}
			newline();
			self.on('keydown', '[contenteditable]', function(evt){
				if (evt.keyCode == 13){
					this.removeAttribute('contenteditable'); // the old input line should not be editable
					// standards use textContent, IE uses innerText
					effect.call($('<p class=response>').appendTo(self),handler(this.textContent || this.innerText));
					newline();
					return false;
				}
			});
		});
	};

And you use it like:

$('div').cli(function(text){
  return 'You wrote: '+text;
});

See the demo. The font there is Peter Hull's VT323.

handler is a function that is passed the text in the input line and should return the text to output. prompt is the prompt string. effect is the function that lets you do fancy things to the output. It is called with this set to a <p> element that is to contain the text, and is passed one parameter, the text to output. It defaults to jQuery.fn.text, just showing the text.

It's not fancy; any actual processing of the text is up to you. Catching special characters like the up-arrow for history is also up to you. It doesn't have the old-fashioned blinking block cursor, since the insertion point caret is not styleable, and faking it is not worth the effort.

If you want a mind-blowingly cool terminal emulator, see mass:werk's termlib. And check out their cool Space Invaders game on their 404 page.

I started using Sass (actually, scssphp, since I'm a PHP troglodyte) and I'm loving it. It makes CSS much cleaner; just having variables makes everything easier. The only catch is whether it would work with the non-standard CSS I use with my CSS parser for behaviors. The good news is that it does, with one caveat.

Continue reading ‘Using parsecss with Sass’ »