diff --git a/src/agenda.js b/src/agenda.js index 37ef3b3..c1ecf30 100644 --- a/src/agenda.js +++ b/src/agenda.js @@ -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 } } diff --git a/src/css/main.css b/src/css/main.css index 6e200b6..f4d773d 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -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 { diff --git a/src/grid.js b/src/grid.js index e47341b..4ab6ec5 100644 --- a/src/grid.js +++ b/src/grid.js @@ -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; @@ -302,9 +297,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; + + function setHeight(height) { viewHeight = height; - dayContentPositions.clear(); - 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) ); - } diff --git a/src/main.js b/src/main.js index d9c42b4..e18f0b2 100644 --- a/src/main.js +++ b/src/main.js @@ -147,10 +147,17 @@ $.fn.fullCalendar = function(options) { // element var _element = this, element = $(_element).addClass('fc'), - elementWidth, - content = $("
").prependTo(_element), // relative for ie6 - contentWidth, - contentHeight; + elementOuterWidth, + content = $("").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'); @@ -158,11 +165,6 @@ $.fn.fullCalendar = function(options) { if (options.theme) { 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); @@ -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]( - $("").appendTo(content), + $("").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(); + 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(function(events) { + ignoreWindowResize++; + view.renderEvents(events); + ignoreWindowResize--; + }); + }else{ + view.renderEvents(events); // don't refetch + } } - 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) - if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) { - fetchEvents(callback); - }else{ - callback(events); // no refetching - } - }); - unfixContentSize(); - view.date = cloneDate(date); - } - 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); + ignoreWindowResize--; } } - // marks other views' events as dirty - function eventsDirtyExcept(exceptView) { // TODO: otherViewsEventsDirty - $.each(viewInstances, function() { - if (this != exceptView) { - this.eventsDirty = true; - } - }); - } - // 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() { @@ -799,6 +780,7 @@ $.fn.fullCalendar = function(options) { view.rerenderEvents(); // needed for IE 7 // TODO: could probably skip recompile }, 0); } + }); diff --git a/src/util.js b/src/util.js index 8afd4b6..34dd981 100644 --- a/src/util.js +++ b/src/util.js @@ -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 diff --git a/tests/liquidwidth.html b/tests/liquidwidth.html new file mode 100644 index 0000000..8785f71 --- /dev/null +++ b/tests/liquidwidth.html @@ -0,0 +1,102 @@ + + + + + + + + + + + +