Hi Laura,
Firstly, you're right - the current Calendar/CalendarGroup API does not really expose/provide the methods required to easily work cell indices.
It does have a couple of index based properties though, cells and cellDates, which can be leveraged to provide the type of functionality you require, while also keeping to the public Calendar interfaces (viz. avoiding private Calendar methods, not relying on implementation details like DOM ids etc.).
The general idea is to:
a). Setup a Selection Listener
In the selection listener...
b). Find the cell index of the date selected using Calendar.cells/cellDates *
c). Look up and down the cellDates array in increments of 7 (Days in a week) and select dates which are ! OOM
The complexities arise around the fact that:
1). CalendarGroup does not have it's own cells/cellDates array, so we need to
i). Find the Calendar (page) for the selected date *
ii). Use this Calendar's cellDates array to drive the selection
2). Since we're 'selecting' inside a selectEvent listener, we run into the issue of recursing infinitely (not fun)
The methods/tasks marked with a * above are ones which I believe should exist as part of the Calendar API. We'll be looking into this for a future release.
Anyhow, here's the code I came up with which attempts to deal with the above issues and seems to work OK. Needs some thorough testing though.
I don't necessarily know if it's faster than re-rendering after applying a renderer, but it seems to be. Also, keep in mind that applying the renderer (or manipulating CSS directly) doesn't really change the selected state of the calendar - just it's visual appearance.
NOTE: you'll need to add code to handle de-selection similarly, but the stucture should be identical.
Let us know if this helps,
- Satyen
<div id="cal1Container"></div>
<script type="text/javascript">
function updateSelection(type, args, obj)
{
// We need this flag to stop re-entrancy for the listener
//(when selectCell is called below)
if (!this.__selectingInternal) {
this.__selectingInternal = true;
var selectedDateArray = args[0][0];
var cal = (!this.pages) ? this : findCalPage(this, selectedDateArray);
if (cal) {
var index = findCellIndex(cal, selectedDateArray);
if (index != -1) {
var DAYS_IN_WEEK = 7;
// Dates Above
for (var i = index - DAYS_IN_WEEK; i >= 0; i -= DAYS_IN_WEEK) {
var nextDate = cal.cellDates[i];
if (!cal.isDateOOM(getDateFromArray(nextDate))) {
// If you don't need selection state, just highlighting;
// you can set a css class instead and drop the re-entrancy check
cal.selectCell(i);
} else {
break;
}
}
// Dates Below
for (var j = index + DAYS_IN_WEEK; j < cal.cellDates.length; j += DAYS_IN_WEEK) {
var nextDate = cal.cellDates[j];
if (!cal.isDateOOM(getDateFromArray(nextDate))) {
cal.selectCell(j);
} else {
break;
}
}
}
}
this.__selectingInternal = false;
}
}
// Some of these next 3 methods should probably be provided (publically) by
// the Calendar/CalendarGroup API
function getDateFromArray(dateArray)
{
return new Date(dateArray[0], dateArray[1]-1, dateArray[2]);
}
function findCellIndex(cal, selectedDateArray)
{
var selectedDateArrayStr = selectedDateArray.join(",");
for (var i = 0; i < cal.cellDates.length; ++i)
{
if (selectedDateArrayStr == cal.cellDates[i].join(","))
{
return i;
}
}
return -1;
}
function findCalPage(calgroup, selectedDateArray)
{
var yr = selectedDateArray[0];
var monthIdx = selectedDateArray[1] - 1;
var pages = calgroup.pages;
for (var i = 0; i < pages.length; ++i)
{
var pageDate = pages[i].cfg.getProperty("pagedate");
if (pageDate.getFullYear() == yr && pageDate.getMonth() == monthIdx)
{
return pages[i];
}
}
return null;
}
function init() {
var cal1 = new YAHOO.widget.CalendarGroup("cal1", "cal1Container", {MULTI_SELECT: true});
cal1.selectEvent.subscribe(updateSelection, cal1, true);
cal1.render();
}
YAHOO.util.Event.addListener(window, "load", init);
</script>