fixed a bunch of incorrect sizing bugs, ie bugs

This commit is contained in:
Adam Shaw 2010-02-15 22:32:43 -08:00
parent 4a26b0ab04
commit e4ea11c3df
6 changed files with 268 additions and 178 deletions

View file

@ -21,7 +21,7 @@ setDefaults({
views.agendaWeek = function(element, options) { views.agendaWeek = function(element, options) {
return new Agenda(element, options, { return new Agenda(element, options, {
render: function(date, delta, width, height, fetchEvents) { render: function(date, delta) {
if (delta) { if (delta) {
addDays(date, delta * 7); addDays(date, delta * 7);
} }
@ -43,9 +43,7 @@ views.agendaWeek = function(element, options) {
); );
this.renderAgenda( this.renderAgenda(
options.weekends ? 7 : 5, options.weekends ? 7 : 5,
this.option('columnFormat'), this.option('columnFormat')
width, height,
fetchEvents
); );
} }
}); });
@ -53,7 +51,7 @@ views.agendaWeek = function(element, options) {
views.agendaDay = function(element, options) { views.agendaDay = function(element, options) {
return new Agenda(element, options, { return new Agenda(element, options, {
render: function(date, delta, width, height, fetchEvents) { render: function(date, delta) {
if (delta) { if (delta) {
addDays(date, delta); addDays(date, delta);
if (!options.weekends) { if (!options.weekends) {
@ -65,9 +63,7 @@ views.agendaDay = function(element, options) {
this.end = this.visEnd = addDays(cloneDate(this.start), 1); this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderAgenda( this.renderAgenda(
1, 1,
this.option('columnFormat'), this.option('columnFormat')
width, height,
fetchEvents
); );
} }
}); });
@ -97,7 +93,8 @@ function Agenda(element, options, methods) {
renderEvents: renderEvents, renderEvents: renderEvents,
rerenderEvents: rerenderEvents, rerenderEvents: rerenderEvents,
clearEvents: clearEvents, clearEvents: clearEvents,
updateSize: updateSize, setHeight: setHeight,
setWidth: setWidth,
shown: resetScroll, shown: resetScroll,
defaultEventEnd: function(event) { defaultEventEnd: function(event) {
var start = cloneDate(event.start); var start = cloneDate(event.start);
@ -115,12 +112,12 @@ function Agenda(element, options, methods) {
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
element.addClass('fc-agenda').css('position', 'relative'); element.addClass('fc-agenda');
if (element.disableSelection) { if (element.disableSelection) {
element.disableSelection(); element.disableSelection();
} }
function renderAgenda(c, colFormat, width, height, fetchEvents) { function renderAgenda(c, colFormat) {
colCnt = c; colCnt = c;
// update option-derived variables // update option-derived variables
@ -261,10 +258,6 @@ function Agenda(element, options, methods) {
} }
updateSize(width, height);
resetScroll();
fetchEvents(renderEvents);
}; };
@ -284,21 +277,35 @@ function Agenda(element, options, methods) {
} }
function updateSize(width, height) { function setHeight(height) {
viewWidth = width;
viewHeight = height; viewHeight = height;
colContentPositions.clear();
slotTopCache = {}; slotTopCache = {};
body.width(width);
body.height(height - head.height()); body.height(height - head.height());
slotHeight = body.find('tr:first div').height() + 1;
bg.css({
top: head.find('tr').height(),
height: height
});
resetScroll(); //TODO: not the best place for this
}
function setWidth(width) {
viewWidth = width;
colContentPositions.clear();
body.width(width);
bodyTable.width(''); bodyTable.width('');
var topTDs = head.find('tr:first th'), var topTDs = head.find('tr:first th'),
stripeTDs = bg.find('td'), stripeTDs = bg.find('td'),
contentWidth = slotSegmentContainer.width(); // body[0].clientWidth isn't reliable here in IE6 clientWidth = slotSegmentContainer.width(); // body[0].clientWidth isn't reliable here in IE6
bodyTable.width(contentWidth); bodyTable.width(clientWidth);
// time-axis width // time-axis width
axisWidth = 0; axisWidth = 0;
@ -312,21 +319,20 @@ function Agenda(element, options, methods) {
); );
// column width // column width
colWidth = Math.floor((contentWidth - axisWidth) / colCnt); colWidth = Math.floor((clientWidth - axisWidth) / colCnt);
setOuterWidth(stripeTDs.slice(0, -1), colWidth); setOuterWidth(stripeTDs.slice(0, -1), colWidth);
setOuterWidth(topTDs.slice(1, -2), colWidth); setOuterWidth(topTDs.slice(1, -2), colWidth);
setOuterWidth(topTDs.slice(-2, -1), contentWidth - axisWidth - colWidth*(colCnt-1)); setOuterWidth(topTDs.slice(-2, -1), clientWidth - axisWidth - colWidth*(colCnt-1));
bg.css({ bg.css({
top: head.find('tr').height(),
left: axisWidth, left: axisWidth,
width: contentWidth - axisWidth, width: clientWidth - axisWidth
height: height
}); });
slotHeight = body.find('tr:first div').height() + 1;
} }
function slotClick(ev) { function slotClick(ev) {
var col = Math.floor((ev.pageX - bg.offset().left) / colWidth), var col = Math.floor((ev.pageX - bg.offset().left) / colWidth),
date = addDays(cloneDate(view.visStart), dit + dis*col), date = addDays(cloneDate(view.visStart), dit + dis*col),
@ -448,7 +454,7 @@ function Agenda(element, options, methods) {
bindDaySegHandlers, bindDaySegHandlers,
modifiedEventId modifiedEventId
); );
updateSize(viewWidth, viewHeight); // might have pushed the body down, so resize setHeight(viewHeight); // might have pushed the body down, so resize
} }
} }

View file

@ -18,6 +18,7 @@
.fc { .fc {
direction: ltr; direction: ltr;
text-align: left;
} }
.fc table { .fc table {
@ -49,6 +50,7 @@ table.fc-header {
.fc-header-center { .fc-header-center {
width: 50%; width: 50%;
text-align: center;
} }
.fc-header-center table { .fc-header-center table {

View file

@ -8,7 +8,7 @@ setDefaults({
views.month = function(element, options) { views.month = function(element, options) {
return new Grid(element, options, { return new Grid(element, options, {
render: function(date, delta, width, height, fetchEvents) { render: function(date, delta) {
if (delta) { if (delta) {
addMonths(date, delta); addMonths(date, delta);
date.setDate(1); date.setDate(1);
@ -43,9 +43,7 @@ views.month = function(element, options) {
this.renderGrid( this.renderGrid(
rowCnt, options.weekends ? 7 : 5, rowCnt, options.weekends ? 7 : 5,
this.option('columnFormat'), this.option('columnFormat'),
true, true
width, height,
fetchEvents
); );
} }
}); });
@ -53,7 +51,7 @@ views.month = function(element, options) {
views.basicWeek = function(element, options) { views.basicWeek = function(element, options) {
return new Grid(element, options, { return new Grid(element, options, {
render: function(date, delta, width, height, fetchEvents) { render: function(date, delta) {
if (delta) { if (delta) {
addDays(date, delta * 7); addDays(date, delta * 7);
} }
@ -76,9 +74,7 @@ views.basicWeek = function(element, options) {
this.renderGrid( this.renderGrid(
1, options.weekends ? 7 : 5, 1, options.weekends ? 7 : 5,
this.option('columnFormat'), this.option('columnFormat'),
false, false
width, height,
fetchEvents
); );
} }
}); });
@ -86,7 +82,7 @@ views.basicWeek = function(element, options) {
views.basicDay = function(element, options) { views.basicDay = function(element, options) {
return new Grid(element, options, { return new Grid(element, options, {
render: function(date, delta, width, height, fetchEvents) { render: function(date, delta) {
if (delta) { if (delta) {
addDays(date, delta); addDays(date, delta);
if (!options.weekends) { if (!options.weekends) {
@ -99,9 +95,7 @@ views.basicDay = function(element, options) {
this.renderGrid( this.renderGrid(
1, 1, 1, 1,
this.option('columnFormat'), this.option('columnFormat'),
false, false
width, height,
fetchEvents
); );
} }
}); });
@ -135,7 +129,8 @@ function Grid(element, options, methods) {
renderEvents: renderEvents, renderEvents: renderEvents,
rerenderEvents: rerenderEvents, rerenderEvents: rerenderEvents,
clearEvents: clearEvents, clearEvents: clearEvents,
updateSize: updateSize, setHeight: setHeight,
setWidth: setWidth,
defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing defaultEventEnd: function(event) { // calculates an end if event doesnt have one, mostly for resizing
return cloneDate(event.start); return cloneDate(event.start);
} }
@ -148,12 +143,12 @@ function Grid(element, options, methods) {
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
element.addClass('fc-grid').css('position', 'relative'); element.addClass('fc-grid');
if (element.disableSelection) { if (element.disableSelection) {
element.disableSelection(); element.disableSelection();
} }
function renderGrid(r, c, colFormat, showNumbers, width, height, fetchEvents) { function renderGrid(r, c, colFormat, showNumbers) {
rowCnt = r; rowCnt = r;
colCnt = c; colCnt = c;
@ -303,9 +298,6 @@ function Grid(element, options, methods) {
} }
updateSize(width, height);
fetchEvents(renderEvents);
}; };
@ -319,22 +311,18 @@ function Grid(element, options, methods) {
} }
function updateSize(width, height) { // does not render/position the events
viewWidth = width;
viewHeight = height;
dayContentPositions.clear();
function setHeight(height) {
viewHeight = height;
var leftTDs = tbody.find('tr td:first-child'), var leftTDs = tbody.find('tr td:first-child'),
tbodyHeight = viewHeight - thead.height(), tbodyHeight = viewHeight - thead.height(),
rowHeight1, rowHeight2; rowHeight1, rowHeight2;
if (options.weekMode == 'variable') { if (options.weekMode == 'variable') {
rowHeight1 = rowHeight2 = Math.floor(tbodyHeight / (rowCnt==1 ? 2 : 6)); rowHeight1 = rowHeight2 = Math.floor(tbodyHeight / (rowCnt==1 ? 2 : 6));
}else{ }else{
rowHeight1 = Math.floor(tbodyHeight / rowCnt); rowHeight1 = Math.floor(tbodyHeight / rowCnt);
rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1); rowHeight2 = tbodyHeight - rowHeight1*(rowCnt-1);
} }
if (tdHeightBug == undefined) { if (tdHeightBug == undefined) {
// bug in firefox where cell height includes padding // bug in firefox where cell height includes padding
var tr = tbody.find('tr:first'), var tr = tbody.find('tr:first'),
@ -342,7 +330,6 @@ function Grid(element, options, methods) {
td.height(rowHeight1); td.height(rowHeight1);
tdHeightBug = rowHeight1 != td.height(); tdHeightBug = rowHeight1 != td.height();
} }
if (tdHeightBug) { if (tdHeightBug) {
leftTDs.slice(0, -1).height(rowHeight1); leftTDs.slice(0, -1).height(rowHeight1);
leftTDs.slice(-1).height(rowHeight2); leftTDs.slice(-1).height(rowHeight2);
@ -350,12 +337,16 @@ function Grid(element, options, methods) {
setOuterHeight(leftTDs.slice(0, -1), rowHeight1); setOuterHeight(leftTDs.slice(0, -1), rowHeight1);
setOuterHeight(leftTDs.slice(-1), rowHeight2); setOuterHeight(leftTDs.slice(-1), rowHeight2);
} }
}
function setWidth(width) {
viewWidth = width;
dayContentPositions.clear();
setOuterWidth( setOuterWidth(
thead.find('th').slice(0, -1), thead.find('th').slice(0, -1),
colWidth = Math.floor(viewWidth / colCnt) colWidth = Math.floor(viewWidth / colCnt)
); );
} }

View file

@ -147,10 +147,17 @@ $.fn.fullCalendar = function(options) {
// element // element
var _element = this, var _element = this,
element = $(_element).addClass('fc'), element = $(_element).addClass('fc'),
elementWidth, elementOuterWidth,
content = $("<div class='fc-content " + tm + "-widget-content' style='position:relative'/>").prependTo(_element), // relative for ie6 content = $("<div class='fc-content " + tm + "-widget-content' style='position:relative'/>").prependTo(_element),
contentWidth, suggestedViewHeight,
contentHeight; resizeUID = 0,
ignoreWindowResize = 0,
date = new Date(),
viewName, // the current view name (TODO: look into getting rid of)
view, // the current view
viewInstances = {};
if (options.isRTL) { if (options.isRTL) {
element.addClass('fc-rtl'); element.addClass('fc-rtl');
@ -159,11 +166,6 @@ $.fn.fullCalendar = function(options) {
element.addClass('ui-widget'); element.addClass('ui-widget');
} }
// view managing
var date = new Date(),
viewName, view, // the current view
viewInstances = {};
if (options.year != undefined && options.year != date.getFullYear()) { if (options.year != undefined && options.year != date.getFullYear()) {
date.setDate(1); date.setDate(1);
date.setMonth(0); date.setMonth(0);
@ -184,14 +186,19 @@ $.fn.fullCalendar = function(options) {
function changeView(v) { function changeView(v) {
if (v != viewName) { if (v != viewName) {
fixContentSize(); ignoreWindowResize++;
if (view) {
if (view.eventsChanged) { var oldView = view;
eventsDirtyExcept(view); if (oldView) {
view.eventsChanged = false; if (oldView.eventsChanged) {
eventsDirty();
oldView.eventDirty = oldView.eventsChanged = false;
} }
view.element.hide(); setMinHeight(content, content.height()); // needs to be first
content.css('overflow', 'hidden');
oldView.element.hide();
} }
if (viewInstances[v]) { if (viewInstances[v]) {
(view = viewInstances[v]).element.show(); (view = viewInstances[v]).element.show();
if (view.shown) { if (view.shown) {
@ -199,51 +206,55 @@ $.fn.fullCalendar = function(options) {
} }
}else{ }else{
view = viewInstances[v] = $.fullCalendar.views[v]( view = viewInstances[v] = $.fullCalendar.views[v](
$("<div class='fc-view fc-view-" + v + "'/>").appendTo(content), $("<div class='fc-view fc-view-" + v + "' style='position:relative'/>").appendTo(content),
options); options);
} }
if (header) { if (header) {
// update 'active' view button // update 'active' view button
header.find('div.fc-button-' + viewName).removeClass(tm + '-state-active'); header.find('div.fc-button-' + viewName).removeClass(tm + '-state-active');
header.find('div.fc-button-' + v).addClass(tm + '-state-active'); header.find('div.fc-button-' + v).addClass(tm + '-state-active');
} }
view.name = viewName = v; view.name = viewName = v;
render(); render();
unfixContentSize(); if (oldView) {
content.css('overflow', ''); // needs to be first
setMinHeight(content, 0);
}
ignoreWindowResize--;
} }
} }
function render(inc, forceUpdateSize) { function render(inc) {
if ((elementWidth = _element.offsetWidth) !== 0) { // visible on the screen if (_element.offsetWidth !== 0) { // visible on the screen
if (!contentHeight || forceUpdateSize) { ignoreWindowResize++;
contentWidth = content.width();
contentHeight = calculateContentHeight(); if (!view.start || inc || date < view.start || date >= view.end) {
} view.render(date, inc || 0); // responsible for clearing events
if (inc || !view.date || date < view.start || date >= view.end) { // !view.date means it hasn't been rendered yet setSize();
fixContentSize();
view.render(date, inc || 0, contentWidth, contentHeight, function(callback) {
// dont refetch if new view contains the same events (or a subset)
if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) { if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) {
fetchEvents(callback); fetchEvents(function(events) {
}else{ ignoreWindowResize++;
callback(events); // no refetching view.renderEvents(events);
} ignoreWindowResize--;
}); });
unfixContentSize(); }else{
view.date = cloneDate(date); view.renderEvents(events); // don't refetch
} }
else if (view.sizeDirty || forceUpdateSize) { }
view.updateSize(contentWidth, contentHeight); else if (view.sizeDirty || view.eventsDirty) {
view.clearEvents();
view.renderEvents(events);
}
else if (view.eventsDirty) {
// ensure events are rerendered if another view messed with them
// pass in 'events' b/c event might have been added/removed
// executed on a changeView
view.clearEvents(); view.clearEvents();
if (view.sizeDirty) {
setSize();
}
view.renderEvents(events); view.renderEvents(events);
} }
elementOuterWidth = element.outerWidth();
view.sizeDirty = false;
view.eventsDirty = false;
if (header) { if (header) {
// update title text // update title text
header.find('h2.fc-header-title').html(view.title); header.find('h2.fc-header-title').html(view.title);
@ -255,65 +266,45 @@ $.fn.fullCalendar = function(options) {
header.find('div.fc-button-today').removeClass(tm + '-state-disabled'); header.find('div.fc-button-today').removeClass(tm + '-state-disabled');
} }
} }
view.sizeDirty = false;
view.eventsDirty = false;
view.trigger('viewDisplay', _element);
}
}
// marks other views' events as dirty view.trigger('viewDisplay', _element);
function eventsDirtyExcept(exceptView) { // TODO: otherViewsEventsDirty ignoreWindowResize--;
$.each(viewInstances, function() {
if (this != exceptView) {
this.eventsDirty = true;
} }
});
} }
// called when any event objects have been added/removed/changed, rerenders // called when any event objects have been added/removed/changed, rerenders
function eventsChanged() { function eventsChanged() {
eventsDirty();
view.clearEvents(); view.clearEvents();
view.renderEvents(events); view.renderEvents(events);
eventsDirtyExcept(view); view.eventsDirty = false;
} }
// marks other views' sizes as dirty // marks other views' events as dirty
function sizesDirtyExcept(exceptView) { function eventsDirty() {
$.each(viewInstances, function() { $.each(viewInstances, function() {
if (this != exceptView) { this.eventsDirty = true;
this.sizeDirty = true;
}
}); });
} }
// called when we know the element size has changed // called when we know the element size has changed
function sizeChanged(fix) { function sizeChanged() {
contentWidth = content.width(); sizesDirty();
contentHeight = calculateContentHeight(); calcSize();
if (fix) { setSize();
fixContentSize();
}
view.updateSize(contentWidth, contentHeight);
if (fix) {
unfixContentSize();
}
sizesDirtyExcept(view);
view.rerenderEvents(); view.rerenderEvents();
} }
// calculate what the height of the content should be // marks other views' sizes as dirty
function calculateContentHeight() { function sizesDirty() {
if (options.contentHeight) { $.each(viewInstances, function() {
return options.contentHeight; this.sizeDirty = true;
} });
else if (options.height) {
return options.height - (header ? header.height() : 0) - vsides(content[0]);
}
return Math.round(contentWidth / Math.max(options.aspectRatio, .5));
} }
/* Event Sources and Fetching /* Event Sources and Fetching
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
@ -411,9 +402,9 @@ $.fn.fullCalendar = function(options) {
var publicMethods = { var publicMethods = {
render: function() { render: function() {
render(0, true); // true forces size to updated sizesDirty();
sizesDirtyExcept(view); eventsDirty();
eventsDirtyExcept(view); render();
}, },
changeView: changeView, changeView: changeView,
@ -590,10 +581,7 @@ $.fn.fullCalendar = function(options) {
return events; // else, return all return events; // else, return all
}, },
rerenderEvents: function() { rerenderEvents: eventsChanged, // TODO: think of renaming eventsChanged
view.rerenderEvents();
eventsDirtyExcept(view);
},
// //
// Event Source // Event Source
@ -734,48 +722,39 @@ $.fn.fullCalendar = function(options) {
/* Resizing /* Resizing
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
var contentSizeFixed = false,
resizeCnt = 0;
function fixContentSize() { function calcSize() {
if (!contentSizeFixed) { if (options.contentHeight) {
contentSizeFixed = true; suggestedViewHeight = options.contentHeight;
content.css({ }
overflow: 'hidden', else if (options.height) {
height: contentHeight suggestedViewHeight = options.height - (header ? header.height() : 0) - vsides(content[0]);
}); }
// TODO: previous action might have caused scrollbars else {
// which will make the window width more narrow, possibly changing the aspect ratio suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));
} }
} }
function unfixContentSize() {
if (contentSizeFixed) { function setSize() {
content.css({ ignoreWindowResize++;
overflow: 'visible', view.setHeight(suggestedViewHeight);
height: '' view.setWidth(content.width());
}); ignoreWindowResize--;
if ($.browser.msie && ($.browser.version=='6.0' || $.browser.version=='7.0')) {
// in IE6/7 the inside of the content div was invisible
// bizarre hack to get this work... need both lines
content[0].clientHeight;
content.hide().show();
}
contentSizeFixed = false;
}
} }
function windowResize() { function windowResize() {
if (!contentSizeFixed) { if (!ignoreWindowResize) {
if (view.date) { // view has already been rendered if (view.start) { // view has already been rendered
var rcnt = ++resizeCnt; // add a delay var uid = ++resizeUID;
setTimeout(function() { setTimeout(function() { // add a delay
if (rcnt == resizeCnt && !contentSizeFixed) { if (uid == resizeUID && !ignoreWindowResize) {
var newWidth = element.width(); if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {
if (newWidth != elementWidth) { ignoreWindowResize++;
elementWidth = newWidth; sizeChanged();
sizeChanged(true);
view.trigger('windowResize', _element); view.trigger('windowResize', _element);
ignoreWindowResize--;
} }
} }
}, 200); }, 200);
@ -789,8 +768,10 @@ $.fn.fullCalendar = function(options) {
// let's begin... // let's begin...
calcSize();
changeView(options.defaultView); changeView(options.defaultView);
// in IE, when in 0x0 iframe, initial resize never gets called, so do this... // in IE, when in 0x0 iframe, initial resize never gets called, so do this...
if ($.browser.msie && !$('body').width()) { if ($.browser.msie && !$('body').width()) {
setTimeout(function() { setTimeout(function() {
@ -800,6 +781,7 @@ $.fn.fullCalendar = function(options) {
}, 0); }, 0);
} }
}); });
return this; return this;

View file

@ -338,6 +338,13 @@ function vmargins(_element) {
function setMinHeight(element, h) {
element.css('min-height', h)[0].style.cssText += ';_height:' + (typeof h == 'number' ? h + 'px' : h);
}
/* Position Calculation /* Position Calculation
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
// nasty bugs in opera 9.25 // nasty bugs in opera 9.25

102
tests/liquidwidth.html Normal file
View file

@ -0,0 +1,102 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
<script type='text/javascript' src='loader.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#calendar').fullCalendar({
//defaultView: 'agendaWeek',
//weekMode: 'variable',
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
},
editable: true,
events: [
{
title: 'All Day Event',
start: new Date(y, m, 1)
},
{
title: 'Long Event',
start: new Date(y, m, d-5),
end: new Date(y, m, d-2)
},
{
id: 999,
title: 'Repeating Event',
start: new Date(y, m, d-3, 16, 0),
allDay: false
},
{
id: 999,
title: 'Repeating Event',
start: new Date(y, m, d+4, 16, 0),
allDay: false
},
{
title: 'Meeting',
start: new Date(y, m, d, 10, 30),
allDay: false
},
{
title: 'Lunch',
start: new Date(y, m, d, 12, 5),
end: new Date(y, m, d, 14, 43),
allDay: false
},
{
title: 'Birthday Party',
start: new Date(y, m, d+1, 19, 0),
end: new Date(y, m, d+1, 22, 30),
allDay: false
},
{
title: 'Click for Google',
start: new Date(y, m, 28),
end: new Date(y, m, 29),
url: 'http://google.com/'
}
]
});
});
</script>
<style type='text/css'>
html {
overflow: auto;
}
body {
margin-top: 40px;
text-align: center;
font-size: 13px;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
}
#calendar {
width: 80%;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>