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) {
return new Agenda(element, options, {
render: function(date, delta, width, height, fetchEvents) {
render: function(date, delta) {
if (delta) {
addDays(date, delta * 7);
}
@ -43,9 +43,7 @@ views.agendaWeek = function(element, options) {
);
this.renderAgenda(
options.weekends ? 7 : 5,
this.option('columnFormat'),
width, height,
fetchEvents
this.option('columnFormat')
);
}
});
@ -53,7 +51,7 @@ views.agendaWeek = function(element, options) {
views.agendaDay = function(element, options) {
return new Agenda(element, options, {
render: function(date, delta, width, height, fetchEvents) {
render: function(date, delta) {
if (delta) {
addDays(date, delta);
if (!options.weekends) {
@ -65,9 +63,7 @@ views.agendaDay = function(element, options) {
this.end = this.visEnd = addDays(cloneDate(this.start), 1);
this.renderAgenda(
1,
this.option('columnFormat'),
width, height,
fetchEvents
this.option('columnFormat')
);
}
});
@ -97,7 +93,8 @@ function Agenda(element, options, methods) {
renderEvents: renderEvents,
rerenderEvents: rerenderEvents,
clearEvents: clearEvents,
updateSize: updateSize,
setHeight: setHeight,
setWidth: setWidth,
shown: resetScroll,
defaultEventEnd: function(event) {
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) {
element.disableSelection();
}
function renderAgenda(c, colFormat, width, height, fetchEvents) {
function renderAgenda(c, colFormat) {
colCnt = c;
// 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) {
viewWidth = width;
function setHeight(height) {
viewHeight = height;
colContentPositions.clear();
slotTopCache = {};
body.width(width);
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('');
var topTDs = head.find('tr:first th'),
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
axisWidth = 0;
@ -312,21 +319,20 @@ function Agenda(element, options, methods) {
);
// column width
colWidth = Math.floor((contentWidth - axisWidth) / colCnt);
colWidth = Math.floor((clientWidth - axisWidth) / colCnt);
setOuterWidth(stripeTDs.slice(0, -1), 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({
top: head.find('tr').height(),
left: axisWidth,
width: contentWidth - axisWidth,
height: height
width: clientWidth - axisWidth
});
slotHeight = body.find('tr:first div').height() + 1;
}
function slotClick(ev) {
var col = Math.floor((ev.pageX - bg.offset().left) / colWidth),
date = addDays(cloneDate(view.visStart), dit + dis*col),
@ -448,7 +454,7 @@ function Agenda(element, options, methods) {
bindDaySegHandlers,
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 {
direction: ltr;
text-align: left;
}
.fc table {
@ -49,6 +50,7 @@ table.fc-header {
.fc-header-center {
width: 50%;
text-align: center;
}
.fc-header-center table {

View file

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

View file

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