mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-09-09 11:22:41 +08:00
"more" link on a cell when too many events. accompanying new options
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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`
|
||||
},
|
||||
|
||||
+10
-2
@@ -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
|
||||
},
|
||||
|
||||
+23
-1
@@ -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';
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -4,43 +4,49 @@
|
||||
|
||||
$.extend(DayGrid.prototype, {
|
||||
|
||||
// A jQuery set of <tbody> 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 <tbody> 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 <tbody> 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 <tbody> 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 = $('<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 <td> elements of the level+col matrix
|
||||
var loneCellMatrix = []; // lookup for <td> 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 = $('<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 = $('<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 = $('<td class="fc-event-container"/>').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
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
|
||||
+10
-5
@@ -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]);
|
||||
|
||||
@@ -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 <tr> 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" <a> links and <td> 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 <td> jQuery elements in the row
|
||||
var limitedNodes; // array of temporarily hidden level <tr> and segment <td> 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" <td> 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 <tr> 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 <td> for each column the segment occupies. will be one for each colspan
|
||||
for (j = 0; j < colSegsBelow.length; j++) {
|
||||
moreTd = $('<td class="fc-more-cell"/>').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 <td> 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 <a> 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 $('<a class="fc-more"/>')
|
||||
.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;
|
||||
}
|
||||
|
||||
});
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
+29
-13
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -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('');
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user