Modified 2009-05-19 to use a simpler technique to make it inline.
OK, one more flexcal
transition, inspired by Stefan Petre's jQuery slot machine. I should have been balancing my checkbook, but my kids thought this was cooler.
$('#slots').flexcal({
transition: function(o){
var pane = o.elements.eq(1-o.currSlide), origTable = pane.find('table');
o.elements.eq(o.currSlide).css({zIndex: 1}).animate({top: -o.$cont.height()}, 'normal', 'easeInBack');
pane.css({top: o.$cont.height(), zIndex: 2}).show().animate({top: 0}, 'normal', 'easeInBack', function(){
// make two identical tables without headers and position them correctly (lined up with the bottom)
var spinners = tableSpinners (origTable, o.gif);
var tables = origTable.clone().add(origTable.clone()).appendTo(pane).
find('caption').remove().end().
css({bottom: 0 , marginBottom: 0, zIndex: 101}).hide();
function dropOne(){
if (spinners.length == 0){
tables.remove();
return;
}
var spinner = spinners.eq(Math.floor(Math.random()*spinners.length));
var h = spinner.height();
var left = spinner.offset().left - origTable.offset().left;
var right = left + spinner.width();
spinners = spinners.not(spinner.remove());
origTable.animate({foo: 0}, { // the {foo:0} seems necessary because we need to animate some property, even if it isn't real
duration: o.duration,
easing: 'easeOutElastic',
step: function(now, fx){
if (fx.state == 0){
tables.show();
fx.start = now = 0;
fx.end = 3*h;
}
tables.eq(0).css(offsetColumn(right, left, h, now));
tables.eq(1).css(offsetColumn(right, left, h, now-h));
},
complete: dropOne
});
}
setTimeout (dropOne, o.duration);
})
},
position: {at: 'top', my: 'top'},
speed: 0,
hideOnOutsideClick: false,
transitionOptions: {
duration: 1500,
gif: '/images/ani-bw.gif'
},
// make room for the inline calendar
shown: function() { $('#slots').height($('#slots').flexcal('box').height()); }
});
$('#slots').flexcal('around', 'commit', function(d){
this.d = d;
this.box().find('td a').removeClass('ui-state-active');
this.box().find('td a[rel="'+$.ui.flexcal.date2string(d)+'"]').addClass('ui-state-active');
this.element.val(this.format(d));
this._trigger('commit', 0, d);
});
$('#slots').flexcal('show');
function tableSpinners(t, gif){
var topRow = t.find('tr:first td, tr:first th'), botRow = t.find('tr:last td'), ret = [];
for(var i = 0; i < topRow.length; ++i){
var topCell = topRow.eq(i), botCell = botRow.eq(i);
ret.push($('<img>').appendTo('body').css(topCell.offset()).
css({
paddingTop: '2px',
paddingBottom: '2px',
position: 'absolute',
width: botCell.outerWidth(true),
// hack to avoid Firefox table height bug
height: t.find('tbody').height()+t.find('thead').height(),
zIndex: 101
}).
attr('src', gif)[0]);
}
return $(ret);
}
// create a css object with bottom = b and clip set to rect(0 r h l) pixels, with
// the top and bottom of that rect offset by b so the clip rect is fixed on the screen
// and offsetting b if it is out of the range -h..h
function offsetColumn (r, l, h, b){
b = b%(2*h)-h; // move b into range
return {bottom: b, clip: ['rect(',b,'px ',r,'px ',b+h,'px ',l,'px)'].join('')};
}
The code also shows how to make the datepicker "inline".