From 2053f4dc21f6488ee0db0fd49ed0ce13a1b5c30e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 26 Jul 2014 18:35:14 -0700 Subject: [PATCH] "more" link on a cell when too many events. accompanying new options --- lumbar.json | 1 + src/Calendar.js | 21 ++++ src/Header.js | 8 ++ src/agenda/AgendaView.js | 7 +- src/basic/BasicView.js | 12 +- src/basic/MonthView.js | 24 +++- src/basic/basic.css | 30 +++++ src/common/DayGrid.events.js | 97 +++++++++------ src/common/DayGrid.js | 15 ++- src/common/DayGrid.limit.js | 230 +++++++++++++++++++++++++++++++++++ src/common/Grid.js | 2 +- src/common/print.css | 42 +++++-- src/util.js | 4 +- 13 files changed, 428 insertions(+), 65 deletions(-) create mode 100644 src/common/DayGrid.limit.js diff --git a/lumbar.json b/lumbar.json index b0a36e9..f3a14b8 100644 --- a/lumbar.json +++ b/lumbar.json @@ -30,6 +30,7 @@ "src/common/Grid.events.js", "src/common/DayGrid.js", "src/common/DayGrid.events.js", + "src/common/DayGrid.limit.js", "src/common/TimeGrid.js", "src/common/TimeGrid.events.js", "src/common/View.js", diff --git a/src/Calendar.js b/src/Calendar.js index 5dea1cd..6c0d443 100644 --- a/src/Calendar.js +++ b/src/Calendar.js @@ -52,6 +52,7 @@ function Calendar(element, instanceOptions) { t.today = today; t.gotoDate = gotoDate; t.incrementDate = incrementDate; + t.zoomToDay = zoomToDay; t.getDate = getDate; t.getCalendar = getCalendar; t.getView = getView; @@ -622,6 +623,26 @@ function Calendar(element, instanceOptions) { date.add(moment.duration(delta)); renderView(); } + + + // Forces navigation to a day-view on the given date. `viewName` is the name of an explicit view to go to. + // If not specified, or 'auto', it will guess the best view based on which buttons are in the header toolbar. + function zoomToDay(newDate, viewName) { + var viewsWithButtons; + + if (fcViews[viewName] === undefined) { // not an available view, or 'auto' + viewsWithButtons = header.getViewsWithButtons(); + if ($.inArray('basicDay', viewsWithButtons) !== -1) { + viewName = 'basicDay'; + } + else { + viewName = 'agendaDay'; // the fallback + } + } + + date = newDate; + changeView(viewName); + } function getDate() { diff --git a/src/Header.js b/src/Header.js index 114c4ee..494bbb7 100644 --- a/src/Header.js +++ b/src/Header.js @@ -14,9 +14,11 @@ function Header(calendar, options) { t.deactivateButton = deactivateButton; t.disableButton = disableButton; t.enableButton = enableButton; + t.getViewsWithButtons = getViewsWithButtons; // locals var el = $(); + var viewsWithButtons = []; var tm; @@ -76,6 +78,7 @@ function Header(calendar, options) { button.removeClass(tm + '-state-hover'); // forget why calendar.changeView(buttonName); }; + viewsWithButtons.push(buttonName); } if (buttonClick) { @@ -196,4 +199,9 @@ function Header(calendar, options) { .removeClass(tm + '-state-disabled'); } + + function getViewsWithButtons() { + return viewsWithButtons; + } + } diff --git a/src/agenda/AgendaView.js b/src/agenda/AgendaView.js index c1f4444..ead2169 100644 --- a/src/agenda/AgendaView.js +++ b/src/agenda/AgendaView.js @@ -336,10 +336,9 @@ $.extend(AgendaView.prototype, { this.dayGrid.destroyEvents(); } - // When rerendering events in IE8, the event elements flash because of this line. - // Comment it out. It's not necessary because a renderEvents is always called subsequently, - // which updates the height. - //this.updateHeight(); + // we DON'T need to call updateHeight() because: + // A) a renderEvents() call always happens after this, which will eventually call updateHeight() + // B) in IE8, this causes a flash whenever events are rerendered View.prototype.destroyEvents.call(this); // call the super-method. will kill `this.segs` }, diff --git a/src/basic/BasicView.js b/src/basic/BasicView.js index 681d25a..3dbfb95 100644 --- a/src/basic/BasicView.js +++ b/src/basic/BasicView.js @@ -44,7 +44,7 @@ $.extend(BasicView.prototype, { this.dayGrid.coordMap.containerEl = this.scrollerEl; // constrain clicks/etc to the dimensions of the scroller this.dayGrid.el = this.el.find('.fc-day-grid'); - this.dayGrid.render(); + this.dayGrid.render(this.hasRigidRows()); View.prototype.render.call(this); // call the super-method }, @@ -150,6 +150,12 @@ $.extend(BasicView.prototype, { }, + // Determines whether each row should have a constant height. Overridable by subclasses. + hasRigidRows: function() { + return false; + }, + + /* Dimensions ------------------------------------------------------------------------------------------------------------------*/ @@ -221,7 +227,9 @@ $.extend(BasicView.prototype, { this.recordScroll(); // removing events will reduce height and mess with the scroll, so record beforehand this.dayGrid.destroyEvents(); - this.updateHeight(); + // we DON'T need to call updateHeight() because: + // A) a renderEvents() call always happens after this, which will eventually call updateHeight() + // B) in IE8, this causes a flash whenever events are rerendered View.prototype.destroyEvents.call(this); // call the super-method }, diff --git a/src/basic/MonthView.js b/src/basic/MonthView.js index 9f0157f..ca0a75d 100644 --- a/src/basic/MonthView.js +++ b/src/basic/MonthView.js @@ -3,7 +3,10 @@ ----------------------------------------------------------------------------------------------------------------------*/ setDefaults({ - fixedWeekCount: true + fixedWeekCount: true, + eventLimit: false, + eventLimitText: 'more', + eventLimitClick: 'auto' }); fcViews.month = MonthView; // register the view @@ -56,6 +59,8 @@ $.extend(MonthView.prototype, { // Overrides the default BasicView behavior to have special multi-week auto-height logic setGridHeight: function(height, isAuto) { + var eventLimit = this.opt('eventLimit'); + isAuto = isAuto || this.opt('weekMode') === 'variable'; // LEGACY: weekMode is deprecated // if auto, make the height of each row the height that it would be if there were 6 weeks @@ -63,7 +68,17 @@ $.extend(MonthView.prototype, { height *= this.rowCnt / 6; } + // is the event limit a constant level number? + if (eventLimit && typeof eventLimit === 'number') { + this.dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after + } + distributeHeight(this.dayGrid.rowEls, height, !isAuto); // if auto, don't compensate for height-hogging rows + + // is the event limit dynamically calculated? + if (eventLimit && typeof eventLimit !== 'number') { + this.dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set + } }, @@ -74,6 +89,13 @@ $.extend(MonthView.prototype, { } return this.opt('fixedWeekCount'); + }, + + + // If dynamically limiting events, signals that all rows need to be a constant height. + hasRigidRows: function() { + var eventLimit = this.opt('eventLimit'); + return eventLimit && typeof eventLimit !== 'number'; } }); diff --git a/src/basic/basic.css b/src/basic/basic.css index 0b91aec..1c9b84d 100644 --- a/src/basic/basic.css +++ b/src/basic/basic.css @@ -15,6 +15,19 @@ min-height: 4em; /* ensure that all rows are at least this tall */ } +/* a "rigid" row will take up a constant amount of height because content-skeleton is absolute */ + +.fc-row.fc-rigid { + overflow: hidden; +} + +.fc-row.fc-rigid .fc-content-skeleton { + position: absolute; + top: 0; + left: 0; + right: 0; +} + /* week and day number styling */ .fc-basic-view .fc-week-number, @@ -45,3 +58,20 @@ .fc-rtl .fc-basic-view .fc-day-number { text-align: left; } + +/* "more" link that represents hidden events */ + +a.fc-more { + margin: 1px 2px; + font-size: .85em; + cursor: pointer; + text-decoration: none; +} + +a.fc-more:hover { + text-decoration: underline; +} + +.fc-limited { /* rows and cells that are hidden because of a "more" link */ + display: none; +} diff --git a/src/common/DayGrid.events.js b/src/common/DayGrid.events.js index 50c2191..4908e4f 100644 --- a/src/common/DayGrid.events.js +++ b/src/common/DayGrid.events.js @@ -4,43 +4,49 @@ $.extend(DayGrid.prototype, { - // A jQuery set of elements, one for each row, with events inside. Attached to the content skeletons. - eventTbodyEls: null, + + rowStructs: null, // an array of objects, each holding information about a row's event-rendering // Render the given events onto the Grid and return the rendered segments renderEvents: function(events) { - var res = this.renderEventRows(events); - var tbodyEls = this.eventTbodyEls = res.tbodyEls; + var rowStructs = this.rowStructs = this.renderEventRows(events); + var allSegs = []; // append to each row's content skeleton this.rowEls.each(function(i, rowNode) { - $(rowNode).find('.fc-content-skeleton > table').append(tbodyEls[i]); + $(rowNode).find('.fc-content-skeleton > table').append( + rowStructs[i].tbodyEl + ); + allSegs.push.apply(allSegs, rowStructs[i].segs); }); - return res.segs; // return segment objects. for the view + return allSegs; // return segment objects. for the view }, // Removes all rendered event elements destroyEvents: function() { - if (this.eventTbodyEls) { - this.eventTbodyEls.remove(); - this.eventTbodyEls = null; + var rowStructs = this.rowStructs || []; + var rowStruct; + + while ((rowStruct = rowStructs.pop())) { + rowStruct.tbodyEl.remove(); } }, // Uses the given events array to generate elements that should be appended to each row's content skeleton. - // Returns an object with properties 'tbodyEls' and 'segs' (which contains all the rendered segment objects). + // Returns an array of rowStruct objects (see the bottom of `renderEventRow`). renderEventRows: function(events) { var view = this.view; var allSegs = this.eventsToSegs(events); var segRows = this.groupSegRows(allSegs); // group into nested arrays var html = ''; - var tbodyNodes = []; + var rowStructs = []; var i; var row; + var rowSegs; // build a large concatenation of event segment HTML for (i = 0; i < allSegs.length; i++) { @@ -55,16 +61,14 @@ $.extend(DayGrid.prototype, { // iterate each row of segment groupings for (row = 0; row < segRows.length; row++) { - segRows[row] = $.grep(segRows[row], renderedSegFilter); // filter out non-rendered segments. reassign array - tbodyNodes.push( - this.renderSegSkeleton(segRows[row])[0] + rowSegs = segRows[row]; + rowSegs = $.grep(rowSegs, renderedSegFilter); // filter out non-rendered segments + rowStructs.push( + this.renderEventRow(row, rowSegs) ); } - return { - tbodyEls: $(tbodyNodes), // array -> jQuery set - segs: flattenArray(segRows) // flatten all rendered segments into one array - }; + return rowStructs; }, @@ -116,14 +120,17 @@ $.extend(DayGrid.prototype, { }, - // Given an array of segments all in the same row, render a element, a skeleton that contains the segments - renderSegSkeleton: function(rowSegs) { + // Given a row # and an array of segments all in the same row, render a element, a skeleton that contains + // the segments. Returns object with a bunch of internal data about how the render was calculated. + renderEventRow: function(row, rowSegs) { var view = this.view; var colCnt = view.colCnt; - var levels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels + var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels + var levelCnt = Math.max(1, segLevels.length); // ensure at least one level var tbody = $(''); - var emptyTds = []; // a sparse array of references to the current row's empty cells, indexed by column - var aboveEmptyTds; // like emptyTds, but for the level above + var segMatrix = []; // lookup for which segments are rendered into which level+col cells + var cellMatrix = []; // lookup for all elements of the level+col matrix + var loneCellMatrix = []; // lookup for elements that only take up a single column var i, levelSegs; var col; var tr; @@ -133,8 +140,8 @@ $.extend(DayGrid.prototype, { // populates empty cells from the current column (`col`) to `endCol` function emptyCellsUntil(endCol) { while (col < endCol) { - // try to grab an empty cell from the level above and extend its rowspan. otherwise, create a fresh cell - td = aboveEmptyTds[col]; + // try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell + td = (loneCellMatrix[i - 1] || [])[col]; if (td) { td.attr( 'rowspan', @@ -145,22 +152,24 @@ $.extend(DayGrid.prototype, { td = $(''); tr.append(td); } - emptyTds[col] = td; + cellMatrix[i][col] = td; + loneCellMatrix[i][col] = td; col++; } } - // Iterate through all levels, and then beyond one. Do this so we have an empty row at the end. - // This empty row comes in handy when styling the height of the content skeleton. - for (i = 0; i < levels.length + 1; i++) { - levelSegs = levels[i]; + for (i = 0; i < levelCnt; i++) { // iterate through all levels + levelSegs = segLevels[i]; col = 0; tr = $(''); - aboveEmptyTds = emptyTds; - emptyTds = []; + segMatrix.push([]); + cellMatrix.push([]); + loneCellMatrix.push([]); - if (levelSegs) { // protect against non-existent last level + // levelCnt might be 1 even though there are no actual levels. protect against this. + // this single empty row is useful for styling. + if (levelSegs) { for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level seg = levelSegs[j]; @@ -168,22 +177,36 @@ $.extend(DayGrid.prototype, { // create a container that occupies or more columns. append the event element. td = $('').append(seg.el); - if (seg.rightCol > seg.leftCol) { + if (seg.leftCol != seg.rightCol) { td.attr('colspan', seg.rightCol - seg.leftCol + 1); } + else { // a single-column segment + loneCellMatrix[i][col] = td; + } + + while (col <= seg.rightCol) { + cellMatrix[i][col] = td; + segMatrix[i][col] = seg; + col++; + } tr.append(td); - col = seg.rightCol + 1; } } emptyCellsUntil(colCnt); // finish off the row - this.bookendCells(tr, 'eventSkeleton'); tbody.append(tr); } - return tbody; + return { // a "rowStruct" + row: row, // the row number + tbodyEl: tbody, + cellMatrix: cellMatrix, + segMatrix: segMatrix, + segLevels: segLevels, + segs: rowSegs + }; }, diff --git a/src/common/DayGrid.js b/src/common/DayGrid.js index 3840cd2..7605b85 100644 --- a/src/common/DayGrid.js +++ b/src/common/DayGrid.js @@ -21,14 +21,15 @@ $.extend(DayGrid.prototype, { // Renders the rows and columns into the component's `this.el`, which should already be assigned. + // isRigid determins whether the individual rows should ignore the contents and be a constant height. // Relies on the view's colCnt and rowCnt. In the future, this component should probably be self-sufficient. - render: function() { + render: function(isRigid) { var view = this.view; var html = ''; var row; for (row = 0; row < view.rowCnt; row++) { - html += this.dayRowHtml(row); + html += this.dayRowHtml(row, isRigid); } this.el.html(html); @@ -46,10 +47,14 @@ $.extend(DayGrid.prototype, { // Generates the HTML for a single row. `row` is the row number. - dayRowHtml: function(row) { + dayRowHtml: function(row, isRigid) { var view = this.view; var classes = [ 'fc-row', 'fc-week' ]; + if (isRigid) { + classes.push('fc-rigid'); + } + if (view.dayRowThemeClass) { // provides the view a hook to inject a theme className classes.push(view.dayRowThemeClass); } @@ -197,7 +202,7 @@ $.extend(DayGrid.prototype, { // Renders a mock "helper" event. `sourceSeg` is the associated internal segment object. It can be null. renderHelper: function(event, sourceSeg) { var helperNodes = []; - var tbodyEls = this.renderEventRows([ event ]).tbodyEls; // render events as usual, receiving tbodys to inject + var rowStructs = this.renderEventRows([ event ]); // inject each new event skeleton into each associated row this.rowEls.each(function(row, rowNode) { @@ -215,7 +220,7 @@ $.extend(DayGrid.prototype, { skeletonEl.css('top', skeletonTop) .find('table') - .append(tbodyEls[row]); + .append(rowStructs[row].tbodyEl); rowEl.append(skeletonEl); helperNodes.push(skeletonEl[0]); diff --git a/src/common/DayGrid.limit.js b/src/common/DayGrid.limit.js new file mode 100644 index 0000000..f4f0cd3 --- /dev/null +++ b/src/common/DayGrid.limit.js @@ -0,0 +1,230 @@ + +/* Methods relate to limiting the number events for a given day on a DayGrid +----------------------------------------------------------------------------------------------------------------------*/ + +$.extend(DayGrid.prototype, { + + + // Limits the number of "levels" (vertically stacking layers of events) for each row of the grid. + // `levelLimit` can be false (don't limit), a number, or true (should be computed). + limitRows: function(levelLimit) { + var rowStructs = this.rowStructs || []; + var row; // row # + var rowLevelLimit; + + for (row = 0; row < rowStructs.length; row++) { + this.unlimitRow(row); + + if (!levelLimit) { + rowLevelLimit = false; + } + else if (typeof levelLimit === 'number') { + rowLevelLimit = levelLimit; + } + else { + rowLevelLimit = this.computeRowLevelLimit(row); + } + + if (levelLimit !== false) { + this.limitRow(row, rowLevelLimit); + } + } + }, + + + // Computes the number of levels a row will accomodate without going outside its bounds. + // Assumes the row is "rigid" (maintains a constant height regardless of what is inside). + // `row` is the row number. + computeRowLevelLimit: function(row) { + var rowEl = this.rowEls.eq(row); // the containing "fake" row div + var rowHeight = rowEl.height(); // TODO: cache somehow? + var trEls = this.rowStructs[row].tbodyEl.children(); + var i, trEl; + + // Reveal one level at a time and stop when we find one out of bounds + for (i = 0; i < trEls.length; i++) { + trEl = trEls.eq(i).removeClass('fc-limited'); // get and reveal + if (trEl.position().top + trEl.outerHeight() > rowHeight) { + return i; + } + } + + return false; // should not limit at all + }, + + + // Limits the given grid row to the maximum number of levels and injects "more" links if necessary. + // `row` is the row number. + // `levelLimit` is a number for the maximum (inclusive) number of levels allowed. + limitRow: function(row, levelLimit) { + var _this = this; + var view = this.view; + var rowStruct = this.rowStructs[row]; + var moreNodes = []; // array of "more" links and DOM nodes + var col = 0; // col # + var cell; + var levelSegs; // array of segment objects in the last allowable level, ordered left-to-right + var cellMatrix; // a matrix (by level, then column) of all jQuery elements in the row + var limitedNodes; // array of temporarily hidden level and segment DOM nodes + var i, seg; + var segsBelow; // array of segment objects below `seg` in the current `col` + var totalSegsBelow; // total number of segments below `seg` in any of the columns `seg` occupies + var colSegsBelow; // array of segment arrays, below seg, one for each column (offset from segs's first column) + var td, rowspan; + var segMoreNodes; // array of "more" cells that will stand-in for the current seg's cell + var j; + var moreTd, moreLink; + + // Iterates through empty level cells and places "more" links inside if need be + function emptyCellsUntil(endCol) { // goes from current `col` to `endCol` + while (col < endCol) { + cell = { row: row, col: col }; + segsBelow = _this.getCellSegs(cell, levelLimit); + if (segsBelow.length) { + td = cellMatrix[levelLimit - 1][col]; + moreLink = _this.renderMoreLink(cell, segsBelow); + td.append(moreLink); + moreNodes.push(moreLink[0]); + } + col++; + } + } + + if (levelLimit && levelLimit < rowStruct.segLevels.length) { // is it actually over the limit? + levelSegs = rowStruct.segLevels[levelLimit - 1]; + cellMatrix = rowStruct.cellMatrix; + + limitedNodes = rowStruct.tbodyEl.children().slice(levelLimit) // get level elements past the limit + .addClass('fc-limited').get(); // hide elements and get a simple DOM-nodes array + + // iterate though segments in the last allowable level + for (i = 0; i < levelSegs.length; i++) { + seg = levelSegs[i]; + emptyCellsUntil(seg.leftCol); // process empty cells before the segment + + // determine *all* segments below `seg` that occupy the same columns + colSegsBelow = []; + totalSegsBelow = 0; + while (col <= seg.rightCol) { + cell = { row: row, col: col }; + segsBelow = this.getCellSegs(cell, levelLimit); + colSegsBelow.push(segsBelow); + totalSegsBelow += segsBelow.length; + col++; + } + + if (totalSegsBelow) { // do we need to replace this segment with one or many "more" links? + td = cellMatrix[levelLimit - 1][seg.leftCol]; // the segment's parent cell + rowspan = td.attr('rowspan') || 1; + segMoreNodes = []; + + // make a replacement for each column the segment occupies. will be one for each colspan + for (j = 0; j < colSegsBelow.length; j++) { + moreTd = $('').attr('rowspan', rowspan); + segsBelow = colSegsBelow[j]; + cell = { row: row, col: seg.leftCol + j }; + moreLink = this.renderMoreLink(cell, [ seg ].concat(segsBelow)); // count seg as hidden too + moreTd.append(moreLink); + segMoreNodes.push(moreTd[0]); + moreNodes.push(moreTd[0]); + } + + td.addClass('fc-limited').after($(segMoreNodes)); // hide original and inject replacements + limitedNodes.push(td[0]); + } + } + + emptyCellsUntil(view.colCnt); // finish off the level + rowStruct.moreEls = $(moreNodes); // for easy undoing later + rowStruct.limitedEls = $(limitedNodes); // for easy undoing later + } + }, + + + // Reveals all levels and removes all "more"-related elements for a grid's row. + // `row` is a row number. + unlimitRow: function(row) { + var rowStruct = this.rowStructs[row]; + + if (rowStruct.moreEls) { + rowStruct.moreEls.remove(); + rowStruct.moreEls = null; + } + + if (rowStruct.limitedEls) { + rowStruct.limitedEls.removeClass('fc-limited'); + rowStruct.limitedEls = null; + } + }, + + + // Renders an element that represents hidden event element for a cell. + // Responsible for attaching click handler as well. + renderMoreLink: function(cell, hiddenSegs) { + var _this = this; + var view = this.view; + + return $('') + .text( + this.getMoreLinkText(hiddenSegs.length) + ) + .on('click', function() { + var date = view.cellToDate(cell); + var clickOption = view.opt('eventLimitClick'); + + if (typeof clickOption === 'string') { // a view name or 'auto' + view.calendar.zoomToDay(date, clickOption); + } + else { + view.trigger( + 'eventLimitClick', + null, + date, + _this.getCellDayEl(cell), // element for the cell's day + hiddenSegs, + _this.getCellSegs(cell) // all segments on that day + ); + } + }); + }, + + + // Generates the text that should be inside a "more" link, given the number of events it represents + getMoreLinkText: function(num) { + var view = this.view; + var opt = view.opt('eventLimitText'); + + if (typeof opt === 'function') { + return opt(num); + } + else { + if (view.opt('isRTL')) { + return opt + ' ' + num + '+'; + } + else { + return '+' + num + ' ' + opt; + } + } + }, + + + // Returns segments within a given cell. + // If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs. + getCellSegs: function(cell, startLevel) { + var segMatrix = this.rowStructs[cell.row].segMatrix; + var level = startLevel || 0; + var segs = []; + var seg; + + while (level < segMatrix.length) { + seg = segMatrix[level][cell.col]; + if (seg) { + segs.push(seg); + } + level++; + } + + return segs; + } + +}); diff --git a/src/common/Grid.js b/src/common/Grid.js index 093d5b9..ae04fc7 100644 --- a/src/common/Grid.js +++ b/src/common/Grid.js @@ -62,7 +62,7 @@ $.extend(Grid.prototype, { var _this = this; this.el.on('mousedown', function(ev) { - if (!$(ev.target).is('.fc-event-container *')) { // not an event element + if (!$(ev.target).is('.fc-event-container *, .fc-more')) { // not an event element or "more" link _this.dayMousedown(ev); } }); diff --git a/src/common/print.css b/src/common/print.css index f51ea69..150f4fc 100644 --- a/src/common/print.css +++ b/src/common/print.css @@ -51,31 +51,47 @@ tbody, /* don't force a min-height on rows (for DayGrid) */ .fc tbody .fc-row { - min-height: 0 !important; + height: auto !important; /* undo height that JS set in distributeHeight */ + min-height: 0 !important; /* undo the min-height from each view's specific stylesheet */ } -/* don't have chunky padding underneath events (for Agenda, basicWeek, basicDay) */ .fc tbody .fc-row .fc-content-skeleton { + position: static; /* undo .fc-rigid */ + /* don't have chunky padding underneath events (for Agenda, basicWeek, basicDay) */ padding-bottom: 0 !important; } -/* Make space at the bottom by putting a non-breaking space in the last row's cells. - :last-child only works with newer browsers */ -.fc tbody .fc-row .fc-content-skeleton tbody tr:last-child td:after { - content: "\000A0"; +/* give back the bottom spacing that was taken away from the content-skeleton's padding (above) */ +/* only works on modern browsers */ +.fc tbody .fc-row .fc-content-skeleton table tr:last-child td { + padding-bottom: 1px; } -/* For IE8, which doesn't understand the above line, give a min-height. - For some reason, IE8 really overexaggerates this value. - Other browsers will already be taller than this. */ +/* sets a min-height on the event skeleton. for IE8. was overexaggerating this, so make small */ .fc tbody .fc-row .fc-content-skeleton table { height: 2em; } -/* For IE8, the table height might get too tall and create gaps between events and day lines. - Vertically centering events within these cells makes it look better */ -.fc-day-grid .fc-event-container { - vertical-align: middle !important; +/* sets a min-height on the event skeleton. for modern browsers (not IE8) */ +.fc tbody .fc-row .fc-content-skeleton table:last-child { + height: 4em; +} + + +/* Undo month-view event limiting. Display all events and hide the "more" links +--------------------------------------------------------------------------------------------------*/ + +.fc-more-cell, +.fc-more { + display: none !important; +} + +.fc tr.fc-limited { + display: table-row !important; +} + +.fc td.fc-limited { + display: table-cell !important; } diff --git a/src/util.js b/src/util.js index 380d25e..3ae19ee 100644 --- a/src/util.js +++ b/src/util.js @@ -82,7 +82,7 @@ function distributeHeight(els, availableHeight, shouldRedistribute) { var newHeight = minOffset - (naturalOffset - naturalHeight); // subtract the margin/padding if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things - $(el).css('min-height', newHeight); + $(el).height(newHeight); } }); } @@ -90,7 +90,7 @@ function distributeHeight(els, availableHeight, shouldRedistribute) { // Undoes distrubuteHeight, restoring all els to their natural height function undistributeHeight(els) { - els.css('min-height', ''); + els.height(''); }